博客:愤怒的泡面 ? Angry Powman

  状态(State),指的是对象的某种形态,在当前形态下可能会拥有不同的行为和属性。状态机(State Machine),指控制对象状态的管理器。

  举个形象例子,在网络游戏中常常用到“状态”这一概念,如在WAR3中有 无敌,虚弱,隐身等角色状态,这些状态可以让角色拥有某种特殊能力。游戏角色也有最基本的状态,假想上至少会有两种:正常、死亡。

  游戏角色的状态不可能会无端端改变,它必须在某种条件下才会变换。比如圣骑士有“神圣护甲”这个技能,一旦使用了这个技能,那么角色就会进入了[无敌]状态,“使用技能”这一行为就是触发[无敌]状态的条件(事件)。再比如,角色在[正常]状态下打怪,但不小心被怪物给打死了,此时生命值为0,就会进入[死亡]状态,当然,如果你信春哥的话,那么还可能会拥有[满状态原地复活]这样的状态。

  总而言之,状态会在某个事件触发之后变更。不同的状态也有可能决定了对象的不同属性和行为。

//一般的状态
void handleState()
{
if (event == quot;使用神圣护甲quot;)
{
state = quot;无敌quot;;
}
else if (event == quot;被怪物打,生命值为0quot;)
{
state = quot;死亡quot;;
}
}

  这是一段伪代码,上面可以很清晰地看出状态的变化,event和state之间并没有直接的关系,但state却因为event而变化。这种是“一般状态”。还有一种就是“开关状态”,比如我们平常开灯关灯的,开关按钮就有[按下]和[弹起]两个状态,我们把按钮按下的话,那么按钮就处于[按下]状态,两种状态是相互影响的。如下:

void handleState()
{
if (press_state == quot;开quot;)
{
press_state = quot;关quot;;
}
else if (press_state == quot;关quot;)
{
press_state = quot;开quot;;
}
}

  这也能算是状态机?没错,这也可以说是状态机。但这只是很简单的逻辑处理。但这样的设计缺少弹性和通用性。而且在实际业务里面逻辑并不可能那么简单,于是有了State模式。像上面这种简单的逻辑,如果用上State模式的话就是大材小用了,这样会把事情复杂化。

状态模式的使用场景
  1.大量分支条件,并且这些条件依赖某些常量的情况下。
  2.行为由的状态决定,并且在运行过程中行为会不断随着状态而变化的情况下。

根据这样的特征,大致可以抽象出这样的一个结构:



这个结构总共由三个部分组成:
1.Context (GameRole)
定义用户感兴趣的接口

2.State (RoleState)
定义所有影响状态的行为的接口

3.Subclasses (Fight, Item, Skill)
定义从State继承的子类,子类实现每一个与Context的状态相关的行为接口

逻辑流程如下:
  1.Context(可以以参数的形式)把某个状态相关的请求委托给具体的Subclasses进行处理。
  2.Subclasses根据自身的特征,以决定应该执行哪些状态处理,并给Context返回一个新的Subclasses实例。
  3.Context接收到新的实例,调用自身相关处理函数,更新状态

  Context在此处充当了“状态机”的角色,亦即State Manager. 而Subclasses的实例则充当用户。用户把具体的状态变更结果提交给Context进行转换。

下面设计一段处理状态的程序:
  1.编写一个游戏角色,有站立,跑步,飞行三种状态。
  2.在每种状态下将根据体力是否充足而改变状态。

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-gt;_state-gt;Stand(this);
}

void run()
{
this-gt;_state-gt;Running(this);
}

void fly()
{
this-gt;_state-gt;Fly(this);
}

private:
GameState* _state;
};

class StandState : public GameState
{
public:
void Running(GameRole* role)
{
if (role-gt;EnoughPower == true)
{
role-gt;SetRoleState(new RunningState());
}
else
{
role-gt;SetRoleState(new StandState());
}
}

void Fly(GameRole* role)
{
if (role-gt;EnoughPower == true)
{
role-gt;SetRoleState(new FlyState());
}
else
{
role-gt;SetRoleState(new RunningState());
}
}
};

class RunningState : public GameState
{
public:
void Stand(GameRole* role)
{
if (role-gt;EnoughPower == true)
{
role-gt;SetRoleState(new FlyState());
}
else
{
role-gt;SetRoleState(new StandState());
}
}

void Fly(GameRole* role)
{
if (role-gt;EnoughPower == true)
{
role-gt;SetRoleState(new FlyState());
}
else
{
role-gt;SetRoleState(new RunningState());
}
}
};

class FlyState : public GameState
{
public:
void Stand(GameRole* role)
{
if (role-gt;EnoughPower == true)
{
role-gt;SetRoleState(new RunningState());
}
else
{
role-gt;SetRoleState(new RunningState());
}
}

void Running(GameRole* role)
{
if (role-gt;EnoughPower == true)
{
role-gt;SetRoleState(new RunningState());
}
else
{
role-gt;SetRoleState(new StandState());
}
}
};

  这是一段相对而言比较单一的代码,当然,这样的逻辑是不可能用在游戏上的,呵呵。这里只是为了演示一下状态的变更。
  
  Subclasses的内部对状态的变换规则进行了逻辑处理,因此它只关心自己的下一个状态是什么。这样由若干个状态类组合在一起,无形中形成了不同状态之间转换的规则,这样使状态机独立了出来,而不必涉及到状态的使用者。
 
锐亚教育

锐亚教育,游戏开发论坛|游戏制作人|游戏策划|游戏开发|独立游戏|游戏产业|游戏研发|游戏运营| unity|unity3d|unity3d官网|unity3d 教程|金融帝国3|8k8k8k|mcafee8.5i|游戏蛮牛|蛮牛 unity|蛮牛