Cave:入门指南
Cave:入门指南
Lesson 17 of 19 • 25 XP
Keep your place in this quest
Log in or sign up for free to subscribe, follow lesson progress, and access more learning content.
随着你的游戏玩法变得更复杂,你最终需要让对象根据它们当前的状态表现出不同的行为。一个敌人可能处于闲置、巡逻、追击、攻击、眩晕或死亡状态。一个门可能是关闭、开启中、开启或锁定状态。一个Boss战可能会经历多个阶段。
这时候,状态机就非常有用了。

在上图中,你可以看到Crave为新项目创建的默认敌人,它的状态机打开在右侧。我们处在“wander”状态内,该状态拥有内部状态,如“random selector”(初始状态,绿色表示)、“go to random”和“idle”。你可以看到状态之间用箭头表示的转换,每个状态都有自己的逻辑,可以是图中展示的Python代码,也可以是逻辑积木。
状态机帮助你将行为组织成清晰的状态,而不是写一个充满不相关条件的大脚本。
本课你将学到:
- 什么是状态。
- 什么是转换。
- 分层状态机为何有用。
- Cave的状态机组件如何与实体配合。
On Enter、On Update和On Exit如何工作。- Python和逻辑积木如何在状态和转换中使用。
目标是先理解思维模型。一旦明白了,编辑器的使用就会更轻松。
什么是状态?
状态描述对象当前正在做什么。

例如,敌人可能有这些状态:
IdlePatrolChaseAttackDead
通常一时间只会有一个状态控制敌人。如果敌人在Patrol状态,它不会同时运行攻击行为。如果处于Dead状态,则不应该继续追击玩家。
这让游戏设计更易理解,因为每个状态有明确职责。
| 状态 | 功能示例 |
|---|---|
Idle |
站立等待 |
Patrol |
在点间移动 |
Chase |
向玩家移动 |
Attack |
播放攻击动画并造成伤害 |
Dead |
禁止移动并播放死亡动画 |
相比于在一个巨大脚本里问“本帧敌人该做什么?”,你可以问“敌人当前处于哪个状态?”
什么是转换?
转换是让状态机从一个状态切换到另一个状态的规则。

例如:
- 敌人经过计时器后由
Idle切换到Patrol。 - 玩家被发现后从
Patrol切到Chase。 - 敌人接近后从
Chase切到Attack。 - 攻击结束后从
Attack切回Chase。 - 血量归零时任何状态切到
Dead。
转换不是行为本身。它是“现在应该切换状态”的决定。
这种分离很重要。Attack状态专注于攻击行为,转换决定何时进入或离开该状态。
分层状态机的优势
Cave采用分层状态机,即状态可以包含子状态。这对共享父级概念的多个行为非常有用。
例如,敌人可以这样组织:
Alive
Idle
Patrol
Chase
Attack
Dead
Idle、Patrol、Chase 和 Attack 都属于更大的 Alive 状态。这样结构更清晰,避免重复逻辑。
初学者项目可以从简单的平铺状态机开始,游戏复杂时分层有助于逻辑整洁。
状态机组件
场景中使用状态机,实体需要一个状态机组件。
组件连接实体与状态机资产。资产定义状态、转换和逻辑,组件在游戏运行中控制实体执行。
这与Cave中的其他系统类似:
| 资产 | 组件 |
|---|---|
| Python Script | Python Component 执行它 |
| Animation | Animation Component 播放它 |
| State Machine | State Machine Component 执行它 |
实际中,敌人实体拥有状态机组件,该组件运行敌人AI状态机。
状态机资产可能有属性,可通过属性面板查看,也可以在组件中局部修改,支持创建针对不同实体设置不同参数的模块化状态机。
状态事件
每个状态可响应三个重要时刻:
| 事件 | 触发时机 | 常见用途 |
|---|---|---|
On Enter |
状态开始时 | 重置计时器、初始化变量、播放动画、选择目标 |
On Update |
状态活动时 | 移动、检测距离、更新计时器 |
On Exit |
离开状态时 | 停止特效、清理临时值 |
举个例子,Attack状态可能如下:
On Enter:播放攻击动画。On Update:等待击中时刻或动画回调。On Exit:清除攻击标记。
这样每个状态就像一个小型的自包含行为。
状态中的Python
状态机可以使用Python编写逻辑。
每个状态的Python代码可使用Cave提供的变量,如entity和scene,控制拥有该状态机组件的实体。
例如,进入状态时播放声音:
cave.playSound("Enemy Alert", volume=0.8)
或者读取实体属性:
health = entity.properties.get("health", 100)
这保证了状态逻辑紧贴行为。
转换中的Python
转换也可使用Python。转换Python代码中,Cave使用变量result。当result为True时,转换发生。例如,切换到Dead状态的转换检查血量:
health = entity.properties.get("health", 100)
result = health <= 0
从Chase到Attack的转换可以检查与玩家距离(如果脚本或属性提供此值):
player = scene.get("Player")
playerPos = player.getTransform().getWorldPosition()
entityPos = entity.getTransform().getWorldPosition()
distanceToPlayer = (playerPos - entityPos).length()
result = distanceToPlayer < 2.0
具体数据取决于你的游戏,但思想相同:转换决定该不该切换。
提示: 转换时,来自当前状态定义的所有局部变量都可用。上述例子中,可在来源状态On Enter时缓存玩家和实体变换,减少每帧的数据获取。
状态机中的逻辑积木
状态机也能使用逻辑积木。
当你想通过视觉方式构建行为而非写Python时,这非常实用。很多玩法任务用逻辑积木连接事件、条件和动作都很易懂。
逻辑积木在状态和转换中工作方式与Python代码一样。状态的逻辑积木和转换的逻辑积木都预先初始化,帮助你快速开始。
你可以根据行为需求混合使用Python和逻辑积木。如果一个状态或转换同时拥有两者,则两者都会执行,满足任一条件转换即可触发。
何时使用状态机
对象具有明显行为模式时使用状态机。
好的例子有:
- 敌人AI。
- Boss阶段。
- 门及可交互对象。
- 任务流程。
- 剧情进度。
- 角色能力状态。
对于简单单一动作对象可能不需状态机,比如拾取物仅播放声音后消失,简单Python脚本或逻辑积木即可。
你应该记住的
状态机将游戏玩法组织为状态和转换。
状态描述当前发生的事。转换决定何时切换。On Enter、On Update 和 On Exit 帮助保持状态专注且易读。
简单行为可能脚本足够,多状态行为用状态机更易理解和扩展。