设计模式:State模式 ? 状态机在网络游戏中的应用

发表于2016-05-18
评论1 1.5k浏览
  状态(State),指的是对象的某种形态,在当前形态下可能会拥有不同的行为和属性。状态机(State Machine),指控制对象状态的管理器。
  举个形象例子,在网络游戏中常常用到“状态”这一概念,如在WAR3中有 无敌,虚弱,隐身等角色状态,这些状态可以让角色拥有某种特殊能力。游戏角色也有最基本的状态,假想上至少会有两种:正常、死亡。
  游戏角色的状态不可能会无端端改变,它必须在某种条件下才会变换。比如圣骑士有“神圣护甲”这个技能,一旦使用了这个技能,那么角色就会进入了[无敌]状态,“使用技能”这一行为就是触发[无敌]状态的条件(事件)。再比如,角色在[正常]状态下打怪,但不小心被怪物给打死了,此时生命值为0,就会进入[死亡]状态,当然,如果你信春哥的话,那么还可能会拥有[满状态原地复活]这样的状态。
  总而言之,状态会在某个事件触发之后变更。不同的状态也有可能决定了对象的不同属性和行为。
//一般的状态
void handleState()
{
    if (event == "使用神圣护甲")
    {
        state = "无敌";
    }
    else if (event == "被怪物打,生命值为0")
    {
        state = "死亡";
    }
  这是一段伪代码,上面可以很清晰地看出状态的变化,event和state之间并没有直接的关系,但state却因为event而变化。这种是“一般状态”。还有一种就是“开关状态”,比如我们平常开灯关灯的,开关按钮就有[按下]和[弹起]两个状态,我们把按钮按下的话,那么按钮就处于[按下]状态,两种状态是相互影响的。如下:
void handleState()
{
    if (press_state == "开")
    {
        press_state = "关";
    }
    else if (press_state == "关")
    {
        press_state = "开";
    }
  这也能算是状态机?没错,这也可以说是状态机。但这只是很简单的逻辑处理。但这样的设计缺少弹性和通用性。而且在实际业务里面逻辑并不可能那么简单,于是有了State模式。像上面这种简单的逻辑,如果用上State模式的话就是大材小用了,这样会把事情复杂化。
状态模式的使用场景
  大量分支条件,并且这些条件依赖某些常量的情况下。
  行为由的状态决定,并且在运行过程中行为会不断随着状态而变化的情况下。
  根据这样的特征,大致可以抽象出这样的一个结构:
  这个结构总共由三个部分组成:
  Context (GameRole)
  定义用户感兴趣的接口
  State (RoleState)
  定义所有影响状态的行为的接口
  Subclasses (Fight, Item, Skill)
  定义从State继承的子类,子类实现每一个与Context的状态相关的行为接口

逻辑流程如下:
  Context(可以以参数的形式)把某个状态相关的请求委托给具体的Subclasses进行处理。
  Subclasses根据自身的特征,以决定应该执行哪些状态处理,并给Context返回一个新的Subclasses实例。
  Context接收到新的实例,调用自身相关处理函数,更新状态
  Context在此处充当了“状态机”的角色,亦即State Manager. 而Subclasses的实例则充当用户。用户把具体的状态变更结果提交给Context进行转换。
  下面设计一段处理状态的程序:
  编写一个游戏角色,有站立,跑步,飞行三种状态。
  在每种状态下将根据体力是否充足而改变状态。
class GameState
{
public:
    void Stand(GameRole* role);
    void Running(GameRole* role);
    void Fly(GameRole* role);
}; 
class GameRole
{
public:
    void SetRoleState(GameState* state)
    {
        _state = state;
    }

public:
    void stand()
    {
        this->_state->Stand(this);
    }

    void run()
    {
        this->_state->Running(this);
    }
    void fly()
    {
        this->_state->Fly(this);
    }
private:
    GameState* _state;
};
class StandState : public GameState
{
public:
    void Running(GameRole* role)
    {
        if (role->EnoughPower == true)
        {
            role->SetRoleState(new RunningState());
        }
        else
        {
            role->SetRoleState(new StandState());
        }
    }
    void Fly(GameRole* role)
    {
        if (role->EnoughPower == true)
        {
            role->SetRoleState(new FlyState());
        }
        else
        {
            role->SetRoleState(new RunningState());
        }
    }
};
class RunningState : public GameState
{
public:
    void Stand(GameRole* role)
    {
        if (role->EnoughPower == true)
        {
            role->SetRoleState(new FlyState());
        }
        else
        {
            role->SetRoleState(new StandState());
        }
    }
    void Fly(GameRole* role)
    {
        if (role->EnoughPower == true)
        {
            role->SetRoleState(new FlyState());
        }
        else
        {
            role->SetRoleState(new RunningState());
        }
    }
};
class FlyState : public GameState
{
public:
    void Stand(GameRole* role)
    {
        if (role->EnoughPower == true)
        {
            role->SetRoleState(new RunningState());
        }
        else
        {
            role->SetRoleState(new RunningState());
        }
    }
    void Running(GameRole* role)
    {
        if (role->EnoughPower == true)
        {
            role->SetRoleState(new RunningState());
        }
        else
        {
            role->SetRoleState(new StandState());
        }
    }
};
  这是一段相对而言比较单一的代码,当然,这样的逻辑是不可能用在游戏上的,呵呵。这里只是为了演示一下状态的变更。
  Subclasses的内部对状态的变换规则进行了逻辑处理,因此它只关心自己的下一个状态是什么。这样由若干个状态类组合在一起,无形中形成了不同状态之间转换的规则,这样使状态机独立了出来,而不必涉及到状态的使用者。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论