(学习笔记)设计模式之状态模式(游戏场景切换)

来源:互联网 发布:java自学还是培训 编辑:程序博客网 时间:2024/06/05 02:13

当某个事物改变本身状态时,一般会通过switch或者if等判断语句去切换相应状态,这样会使代码太多,逻辑复杂。

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不同状态的一系列类里面。

状态模式的结构代码:

//状态模式public class Context//状态拥有者{    private IState mState;//私有变量m开头    public void SetState(IState state)//设置状态    {        mState = state;    }    public void Handle(int arg)    {        mState.Handle(arg);    }}public interface IState//状态借口{   void Handle(int args);//传递类型不同}public class ConcreteStateA:IState//具体状态{    private Context mContext;//为了指出当前状态属于哪一个对象    public ConcreteStateA(Context context)    {        mContext = context;    }    public void Handle(int args)    {        Debug.Log("ConcreteStateA:" + args);        if(args>10)        {            mContext.SetState(new ConcreteStateB(mContext));        }    }}public class ConcreteStateB:IState{    private Context mContext;//为了指出当前状态属于哪一个对象    public ConcreteStateB(Context context)    {        mContext = context;    }    public void Handle(int args)    {        Debug.Log("ConcreteStateB:" + args);        if(args<=10)        {            mContext.SetState(new ConcreteStateA(mContext));        }    }}private void Start(){    Context context = new Context();//实例化一个状态拥有者    context.SetState(new ConcreteStateA(context));//给状态拥有者一个默认状态,并且告诉这个默认状态指向自身    context.Handle(5);}


状态模式在游戏场景切换时候的应用:

有三个场景:StartGame,MainMenu,BattleScene.

第1场景有个图片,第二个场景有个按钮,第三个场景无.

接口类:

   public class IScneneState//接口,共有父类    {    private string mSceneName;//名字    protected SceneStateControll mController;//状态拥有者    public IScneneState(string sceneName,SceneStateControll controll)    {        mSceneName = sceneName;//        mController = controll;    }    public string SceneName    {        get { return mSceneName; }    }    //每次进入到这个状态的时候调用    public virtual void StateStart() { }    public virtual void StateEnd() { }    //更新场景时候用    public virtual void StateUpdate() { }    }
状态切换,拥有者

public class SceneStateControll//负责状态切换{    private IScneneState mState;    private AsyncOperation mAo;    private bool mIsRunStart = false;    public void SetState(IScneneState state, bool isloadScene = true)    {        if (mState != null)        {            mState.StateEnd();//让上一个场景做一下清理工作        }        mState = state;        //SceneManager.LoadScene(mState.SceneName);        if (isloadScene)        {            mAo = SceneManager.LoadSceneAsync(mState.SceneName);            mIsRunStart = false;        }        else        {            mState.StateStart();            mIsRunStart = true;        }    }    public void StateUpdate()    {        if (mAo != null && mAo.isDone == false) return;//场景正在加载        if(mIsRunStart==false&& mAo!=null&&mAo.isDone==true)        {            mState.StateStart();            mIsRunStart = true;        }        if(mState!=null)        {             mState.StateUpdate();        }    }    }
StartGamge状态

 class StartState:IScneneState    {    public StartState(SceneStateControll controll):base("01StartGame", controll)    {     }    private Image mLogo;    private float mSmoothingTime = 1;//颜色变化速度    private float mWaitTime = 2;    private float mWaitTimer = 0;//计时器    public override void StateStart()    {        mLogo = GameObject.Find("logo").GetComponent<Image>();        mLogo.color = Color.black;        Debug.Log(mLogo.color);    }    public override void StateUpdate()    {        mLogo.color = Color.Lerp(mLogo.color, Color.white, mSmoothingTime * Time.deltaTime);        mWaitTime -= Time.deltaTime;       if(mWaitTime<=0)        {            mController.SetState(new MainMenuState(mController));//切换状态        }    }}

MainMenuScene场景状态

   public class MainMenuState: IScneneState    {    public MainMenuState(SceneStateControll controller) : base("02MainMenuScene", controller)    {    }    private Button mStartButton;    public override void StateStart()    {        GameObject.Find("startgame").GetComponent<Button>().onClick.AddListener(OnStartButtonClick);    }    private void OnStartButtonClick()    {        mController.SetState(new BattleState(mController));    }}

优点:

1、封装了转换规则。    

2、枚举可能的状态,在枚举状态之前需要确定状态种类。   

3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。    

4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。    

5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

缺点:

1、状态模式的使用必然会增加系统类和对象的个数。       

2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。       

3、状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

原创粉丝点击