状态机在游戏实现中的使用

状态模式是在我们游戏开发中非常常用的一个设计模式。状态模式的特点就是将状态和行为分离,每一个状态下只执行当前状态的行为,这样就将复杂的行为逻辑分为一个个不同状态下的行为逻辑,代码可维护性大大提高。

1.游戏的应用场景

玩家可以控制角色在场景中移动,攻击,飞行,静止不动或者被敌人攻击。在每一个状态下,玩家的动画是不一样的,并且在飞行状态玩家不能进行攻击,在受击状态下,玩家不能移动。
这就是典型的状态模式的需求——在不同的状态下有不同的行为模式。

上图是各个状态之间的转化,有了状态转化图,我们就可以着手开始写状态机的代码了,但在这之前我们先复习一下状态模式的基础内容。

2.状态模式

  • StateM:用于维护和调度所有State
  • State:状态的基类
  • Idle/Run:这里画出了Idle和Run两个状态

这里我们只实现一个最基本的状态机,状态的转换会导致上一个状态结束(即调用leave),状态的进入会调用enter方法。pause方法被调用的情况是在当前状态进行切换,但状态并没有结束,只是产生了一个子状态,当子状态结束后,当前状态又会恢复(resume)。

class StateM(object):

    def __init__(self):
        self._states = {}
        self._curr_state = None

    def add_state(self, name, state):
        self._states[name] = state
        state.statem = self

    def get_curr_state(self):
        return self._curr_state

    def call_method(self, method, *args, **kwargs):
        curr_state = self.get_curr_state()
        if curr_state and hasattr(curr_state, methed):
            getattr(curr_state, method)(*args, **kwargs)

    def change_to(self, name, *args, **kwargs):
        if self._curr_state:
            self._curr_state.leave()
        self._curr_state = self._states[name]
        self._curr_state.enter(*args, **kwargs)

StateM类change_to接口用于切换状态,call_method用于调用当前状态的方法。

class State(object):
    def enter(self, *args, **kwargs):
        pass

    def leave(self):
        pass

    def pause(self):
        pass

    def resume(self):
        pass


class Idle(State):
    def enter(self):
        super(Idle, self).enter()
        # 播放待机动画

    def play_fly(self):
        self.statem.change_to("fly")

    ...

...

# main
self.statem = StateM()
self.statem.add_state("idle", Idle())
self.statem.add_state("fly",  Fly())
self.statem.add_state("atk",  Attack())
...

self.statem.change_to("idle")