游戏框架之状态机(一)

近期可能会更新多一点博客更新。

或许是这个样子,毕竟我是很懒的人,能在笔记本上做笔记的事情,我是从来不会再博客上留下痕迹的。

但涉及的框架知识,肯定要经常会回顾与更改,索性就拿上博客做为一个记录。

以后再要去更改的时候也方便一点。


作为进阶,当然是在参考了成熟的游戏框架之后所具有的新的想法。

所代表的实际意义不明,但起码能给与没有框架之说的项目一个更好的开发思路。

这里不提及MVC等理论性大于实践性的框架,毕竟研究透彻之后才能结合unity达到一个比较好的效果,不然在此之前无实际作用。

因为unity以Component组件方式就已经算是一种框架了。



讲讲正文:

首先先要明白为什么要用这个状态机。

我的解释是UI框架,角色控制,AI等等

具体可以了解下

http://www.manew.com/thread-41889-1-1.html

他这个例子是UI整个框架切换就是用的状态机。


来看下整个思路。

首先有个IState的接口类。

有一个状态管理类StateMachine来控制状态的注册,切换,以及增删查(很像数据库有没有)

每一个状态都是一个单独的类(UI可以不用,可以用一个类注册,然后用不同的回调函数做响应)继承IState接口。


所以我们只需要控制管理类StateMachine就能实现状态机的改变。

是不是很棒,上代码


using UnityEngine;
using System.Collections;

public interface IState {
    /// <summary>
    /// 获取这个状态机的状态
    /// </summary>
    /// <returns></returns>
    /// 

    uint GetStateID();
    /// <summary>
    /// 进入这个状态
    /// </summary>
    /// <param name="machine">状态机</param>
    /// <param name="PrevState">上一个状态</param>
    /// <param name="param1">参数1</param>
    /// <param name="param2">参数2</param>
    void OnEnter(StateMachine machine ,IState PrevState ,object param1, object param2);

    /// <summary>
    /// 离开当前状态
    /// </summary>
    /// <param name="nextState">下一个进入状态</param>
    /// <param name="param1">参数1</param>
    /// <param name="param2">参数2</param>
    void OnLeave(IState nextState, object param1, object param2);

    void OnUpdate();

    void OnFixedUpdate();

    void OnLeteUpdate();
}

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class StateMachine
{
    /// <summary>
    /// 所有的状态集合
    /// </summary>
    private Dictionary<uint, IState> mStateDir = null;

    /// <summary>
    /// 当前状态
    /// </summary>
    private IState mCurrentState = null;

    /// <summary>
    /// 当前状态
    /// </summary>
    public IState CurrentState
    {
        get
        {
            return mCurrentState;
        }
    }
    
    /// <summary>
    /// 当前状态id
    /// </summary>
    public uint CurrentId
    {
        get
        {
            return mCurrentState ==null ?0:mCurrentState.GetStateID();
        }
    }

    public StateMachine()
    {
        mStateDir = new Dictionary<uint, IState>();
        mCurrentState = null;
    }

    /// <summary>
    /// 注册一个状态
    /// </summary>
    /// <param name="state">状态对象</param>
    /// <returns>成功还是失败</returns>
    public bool RegisterState(IState state)
    {
        if(state ==null)
        {
            Debug.LogError("StateMachine.RegisterState state is null");
            return false;
        }
        if(mStateDir.ContainsKey(state.GetStateID()))
        {
            Debug.LogError("state have this key,but stateID =" + state.GetStateID());
            return false;
        }
        mStateDir.Add(state.GetStateID(),state);
        return true;
    }

    /// <summary>
    /// 移除一个状态
    /// </summary>
    /// <param name="stateId">状态Id</param>
    /// <returns>当状态不存在或者状态正在运行,那么返回false</returns>
    public bool RemoveState(uint stateId)
    {
        if(!mStateDir.ContainsKey(stateId))
        {
            return false;
        }
        if(mCurrentState != null && mCurrentState.GetStateID() ==stateId)
        {
            return false;
        }
        mStateDir.Remove(stateId);
        return true;
    }


    /// <summary>
    /// 获取一个状态
    /// </summary>
    /// <param name="stateId">状态id</param>
    /// <returns></returns>
    public IState GetStart(uint stateId)
    {
        IState state = null;
        mStateDir.TryGetValue(stateId, out state);

        return state;
    }

    /// <summary>
    /// 停止当前状态
    /// </summary>
    /// <param name="param1">参数1</param>
    /// <param name="param2">参数2</param>
    public void StopState(object param1 ,object param2)
    {
        if(mCurrentState ==null)
        {
            return;
        }
        mCurrentState.OnLeave(null, param1, param2);
        mCurrentState = null;
    }

    /// <summary>
    /// 切换状态的回调
    /// </summary>
    public BetweenSwitchState BetweenSwitchStateCallBack = null;
    
    /// <summary>
    /// 切换状态回调委托
    /// </summary>
    /// <param name="from">当前状态</param>
    /// <param name="to">要跳转的状态</param>
    /// <param name="param1">参数1</param>
    /// <param name="param2">参数2</param>
    public delegate void BetweenSwitchState(IState from, IState to, object param1, object param2);

    /// <summary>
    /// 切换状态
    /// </summary>
    /// <param name="newStateId">要切换状态Id</param>
    /// <param name="param1">参数1</param>
    /// <param name="param2">参数2</param>
    /// <returns>如果不存在这个状态或者当前状态等于要切换的状态Id,返回失败</returns>
    public bool SwitchState(uint newStateId, object param1,object param2)
    {
        if(mCurrentState != null &&mCurrentState.GetStateID() ==newStateId)
        {
            return false;
        }
        IState newState = null;
        mStateDir.TryGetValue(newStateId, out newState);

        if(newState ==null)
        {
            return false;
        }
        if(mCurrentState !=null)
        {
            mCurrentState.OnLeave(newState, param1, param2);
        }
        IState oldState = mCurrentState;
        mCurrentState = newState;
        if(BetweenSwitchStateCallBack != null)
        {
            BetweenSwitchStateCallBack(oldState, mCurrentState, param1, param2);
        }
        newState.OnEnter(this, oldState, param1, param2);

        return true;
    }


    /// <summary>
    /// 判断当前状态是否是某个状态
    /// </summary>
    /// <param name="stateId"></param>
    /// <returns></returns>
    public bool IsInState(uint stateId)
    {
        return mCurrentState == null ? false : mCurrentState.GetStateID() == stateId;
    }

    public void OnUpdate()
    {
        if(mCurrentState != null)
        {
            mCurrentState.OnUpdate();
        }
    }

    public void OnFixedUpdate()
    {
        if (mCurrentState != null)
        {
            mCurrentState.OnFixedUpdate();
        }
    }

    public void OnLeteUpdate()
    {
        if (mCurrentState != null)
        {
            mCurrentState.OnLeteUpdate();
        }
    }
}


这里我创建了一个cube切换状态来作为测试

using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour {
    [HideInInspector]
    public StateMachine PlayStateMachine = new StateMachine();

    /// <summary>
    /// 角色状态ID
    /// </summary>
    public enum StateType:uint
    {
        LeftRight=0,
        UpDown=1,
    }
    void Awake()
    {
        //注册状态
        PlayStateMachine.RegisterState(new LeftRightState(this));
        PlayStateMachine.RegisterState(new UpDownState(this));
    }

    void Update()
    {
        PlayStateMachine.OnUpdate();
    }

    void FixedUpdate()
    {
        PlayStateMachine.OnFixedUpdate();
    }

    void LeteUpdate()
    {
        PlayStateMachine.OnLeteUpdate();
    }


    void OnGUI()
    {
        if(GUI.Button(new Rect(0,0,100,100),"leftright"))
        {
            //切换状态
            PlayStateMachine.SwitchState((uint)StateType.LeftRight, null, null);
        }
        else if (GUI.Button(new Rect(100, 100, 100, 100), "updown"))
        {
            //切换状态
            PlayStateMachine.SwitchState((uint)StateType.UpDown, null, null);
        }
    }
}


using UnityEngine;
using System.Collections;

public class LeftRightState : IState {
    /// <summary>
    /// 当前角色控制脚本引用
    /// </summary>
    Test mTest = null;
    public LeftRightState(Test test)
    {
        mTest = test;
    }

    uint IState.GetStateID()
    {
        return (uint)Test.StateType.LeftRight;
    }

    void IState.OnEnter(StateMachine machine, IState PrevState, object param1, object param2)
    {
        Debug.Log("Test LeftRight OnEnter");
    }

    void IState.OnLeave(IState nextState, object param1, object param2)
    {
        Debug.Log("Test LeftRight OnLeave");
    }


    private bool isLeft = true;
    void IState.OnUpdate()
    {
        if(isLeft)
        {
            mTest.transform.position += new UnityEngine.Vector3(-0.1f, 0, 0);
            if(mTest.transform.position.x <= -1.5f)
            {
                isLeft = false;
            }
        }
        else
        {
            mTest.transform.position += new UnityEngine.Vector3(0.1f, 0, 0);
            if (mTest.transform.position.x >= 1.5f)
            {
                isLeft = true;
            }
        }
        
    }

    void IState.OnFixedUpdate()
    {
        
    }

    void IState.OnLeteUpdate()
    {
        
    }
}

using UnityEngine;
using System.Collections;

public class UpDownState : IState
{
        /// <summary>
    /// 当前角色控制脚本引用
    /// </summary>
    Test mTest = null;
    public UpDownState(Test test)
    {
        mTest = test;
    }


    uint IState.GetStateID()
    {
        return (uint)Test.StateType.UpDown;
    }

    void IState.OnEnter(StateMachine machine, IState PrevState, object param1, object param2)
    {
        Debug.Log("Test UpDown OnEnter");
    }

    void IState.OnLeave(IState nextState, object param1, object param2)
    {
        Debug.Log("Test UpDown OnLeave");
    }

    private bool isUp = true;
    void IState.OnUpdate()
    {
        if(isUp)
        {
            mTest.transform.position += new UnityEngine.Vector3(0f, 0.1f, 0);
            if (mTest.transform.position.y >= 1.5f)
            {
                isUp = false;
            }
        }
        else
        {
            mTest.transform.position += new UnityEngine.Vector3(0f, -0.1f, 0);
            if (mTest.transform.position.y <= -1.5f)
            {
                isUp = true;
            }
        }
    }

    void IState.OnFixedUpdate()
    {
        
    }

    void IState.OnLeteUpdate()
    {
        
    }
}

总体来说 功能很简单 但是,其核心思想还是很不错的。

可以拓展为UI的控制加载,NPC AI的控制,角色的状态机 等等。

只为抛砖引玉!



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值