一句话定义:状态机:把对象的所有可能情况分成互斥的几种"状态",明确规定状态之间如何切换。
本质上是对实际情况的一种分类讨论。
状态机解决的是:同一个对象,在不同状态下,对同一输入的不同响应问题。
想象一个游戏场景,你操作的角色需要进行不同的动作。 假设角色有这些状态:站立、跑步、跳跃、攻击、受击
刚开始的时候,你打算用if-else来解决
先来定义几个变量保存这些状态:
is_jumping =
False
is_attacking =
False
is_running =
False
is_hurt =
False
is_standing =
False
根据不同状态进行不同形态的攻击:
def
on_attack_button():
if is_jumping
and
not is_attacking
and
not is_hurt:
do_air_attack()
elif is_running
and
not is_attacking
and
not is_hurt:
do_dash_attack()
elif is_standing
and
not is_attacking
and
not is_hurt:
do_normal_attack()
# 还要考虑29种其他组合的合理性
问题来了:
状态机的要素分为4个要素,即:现态、条件、动作、次态。 “现态”和“条件”是因,“动作”和“次态”是果。
(1)现态:是指当前所处状态;
(2)条件:又称为“事件”。当条件被满足时,将会触发一个动作,或者执行一次状态的迁移。
(3)动作:条件满足后执行的动作。动作不是必须的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
(4)次态:条件满足后要迁移往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
核心思路: 任何时刻,角色只能处于一个状态
因此很自然的,我们定义一个变量表示角色的状态:
state =
"站立"
# 只有一个变量
从状态到状态的转换,我们也需要定义:
| 状态(现态) | 状态描述 | 条件(事件) | 动作 | 次态 |
|---|---|---|---|---|
| 站立 | 默认待机状态 | 按方向键 | 播放跑步动画 | 跑步 |
| 按跳跃键 | 播放跳跃动画 | 跳跃 | ||
| 按攻击键 | 播放攻击动画 | 攻击 | ||
| 被打中 | 播放受击动画 | 受击 | ||
| 跑步 | 水平移动中 | 松开方向键 | - | 站立 |
| 按跳跃键 | 播放跳跃动画 | 跳跃 | ||
| 按攻击键 | 播放攻击动画 | 攻击 | ||
| 被打中 | 播放受击动画 | 受击 | ||
| 跳跃 | 空中状态 | 落地 | - | 站立 |
| 按攻击键 | 播放空中攻击动画 | 攻击 | ||
| 被打中 | 播放受击动画 | 受击 | ||
| 攻击 | 攻击动作中 | 动画结束 | - | 站立 |
| 被打中 | 播放受击动画 | 受击 | ||
| 受击 | 受击硬直中 | 硬直结束 | - | 站立 |
flowchart LR
subgraph 基础状态
站立[站立]
跑步[跑步]
end
subgraph 动作状态
跳跃[跳跃]
攻击[攻击]
受击[受击]
end
站立 -->|方向键| 跑步
跑步 -->|松开| 站立
站立 -->|跳跃键| 跳跃
跑步 -->|跳跃键| 跳跃
跳跃 -->|落地| 站立
站立 -->|攻击键| 攻击
跑步 -->|攻击键| 攻击
跳跃 -->|攻击键| 攻击
攻击 -->|动画结束| 站立
站立 -->|被打中| 受击
跑步 -->|被打中| 受击
跳跃 -->|被打中| 受击
攻击 -->|被打中| 受击
受击 -->|硬直结束| 站立
最后我们来实现不同形态的攻击(按攻击键):
def
on_attack_button():
if state ==
"站立":
# 站立时的攻击
do_normal_attack()
state =
"攻击"
elif state ==
"跑步":
# 跑步时的攻击
do_dash_attack()
state =
"攻击"
elif state ==
"跳跃":
# 跳跃时的攻击
do_air_attack()
state =
"攻击"
# 其他状态按攻击键无效,不用写
| 布尔变量组合 | 状态机 | |
|---|---|---|
| 5个状态 | 最多32种组合要考虑 | 只有5种情况 |
| 加新状态 | 所有if都要检查 | 只加新状态的转换 |
| 非法情况 | 要手动排除 | 根本不存在 |
代码的核心思路转变就是:
从"用多个变量组合描述状态"到"用单一变量明确状态"
核心难点是 如何定义状态 以做到互斥。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048892/viewspace-3106444/ ,如需转载,请注明出处,否则将追究法律责任。