关于 godot-state-machine-advanced
面向 Godot 开发者的状态机技能,涵盖扁平 FSM、分层状态机、下推栈和并发逻辑。它通过脚本与路由规范,帮助构建分层游戏或 AI 行为,并强调安全转换和状态生命周期管理。
主要功能
- 01分层状态委派
- 02下推状态堆栈与恢复
- 03转换守卫与共享上下文
- 04并发状态机编排
- 05动画与计时器同步
适用场景
- 01构建嵌套的移动与攻击状态
- 02暂停或中断游戏后恢复
- 03阻止无效状态转换
- 04协调移动与武器行为
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ thedivergentai/ game-dev-agentic-skills --skill godot-state-machine-advanced安装后在 Claude Code 中输入/godot-state-machine-advanced确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/hsm-implementation-cookbook.mdmigration-notes.mdscripts/hsm_animation_syncer.gdhsm_concurrent_logic.gdhsm_hierarchical_base.gdhsm_logic_state.gdhsm_pushdown_stack.gdhsm_reentry_aware_state.gdhsm_resource_state_loader.gdhsm_state_context.gdhsm_state_history_logger.gdhsm_state_timer_component.gdhsm_transition_guard.gdpushdown_automaton.gd详细介绍
可用脚本
hsm_hierarchical_base.gd
高级 HSM 基础委派器,用于将物理和输入传播到子状态。
hsm_pushdown_stack.gd
专业的下推自动机,用于堆叠可中断状态(暂停/菜单)。
hsm_state_context.gd
解耦的上下文对象模式,用于在状态之间传递持久数据。
hsm_transition_guard.gd
专家级转换验证逻辑,用于防止非法状态变更。
hsm_animation_syncer.gd
自动同步逻辑与 AnimationTree,并根据状态执行跳转逻辑。
hsm_concurrent_logic.gd
用于编排并行状态机(例如,移动 + 攻击)。
hsm_resource_state_loader.gd
使用自定义 Godot 资源(.tres)以数据驱动的方式定义状态。
hsm_reentry_aware_state.gd
处理从堆栈恢复与全新进入事件之间的差异。
hsm_state_history_logger.gd
用于跟踪状态转换历史和堆栈深度的调试环形缓冲区。
hsm_state_timer_component.gd
用于眩晕或冲刺等有限状态的自动转换组件。
必须:对于层级 / 下推 / 守卫,请阅读 hsm_hierarchical_base.gd、hsm_pushdown_stack.gd、hsm_transition_guard.gd(以及用于叶节点行为的 hsm_logic_state.gd)。
决策树 — 选择哪种状态机?
| 需求 | 选择 | 必须使用的脚本 |
|---|---|---|
| 少量互斥状态,无嵌套 | 扁平 FSM | hsm_logic_state.gd + 精简父级 |
| 嵌套子状态(移动/空中/攻击子状态) | HSM | hsm_hierarchical_base.gd |
| 中断叠加状态(眩晕/菜单/对话),之后恢复 | 下推 | hsm_pushdown_stack.gd + hsm_reentry_aware_state.gd |
| 并行职责(移动 + 武器) | 并发 | hsm_concurrent_logic.gd |
| 每个 tick 按评分选择最佳动作 | 效用成本轮询 | 专家模式 §3 + hsm_transition_guard.gd |
绝对不要做(状态机专家规则)
层级与委派
- 绝不要忘记向子状态传播物理/输入 — 在 HSM 中,如果未从父级的
_physics_process调用child.physics_update(),子状态逻辑就会失去驱动。 - 绝不要使用过深的嵌套(>3 层) — 层级过深会造成“状态意大利面”。如果逻辑如此复杂,请考虑使用行为树或效用 AI。
转换与生命周期
- 绝不要在调用 enter() 前未先调用 exit() — 跳过退出逻辑会使计时器、补间动画或音频循环在后台持续运行,造成资源泄漏。
- 绝不要在转换帧期间修改状态 — 在
enter()内重入调用transition_to()会导致递归崩溃。如果必须立即进行子转换,请使用call_deferred。 - 绝不要将状态名称硬编码为字符串 — 像
transition_to("Idel")这样的拼写错误会造成隐蔽问题。请使用基于class_name的检查或常量。
架构与上下文
- 绝不要使用全局单例存储状态数据 — 将状态耦合到
GameManager.player_health会导致状态无法复用。请传递Context对象。 - 绝不要无限推入状态 — 在下推自动机中,每次
push_state都必须有后续处理计划(pop_state),以避免堆栈溢出。 - 绝不要假设状态重新进入总是全新开始 — 从堆栈弹出并恢复时,通常应跳过“进入音效/视觉效果”;请使用重新进入标志。
实现 — 脚本是唯一可信来源
切勿复制内联 HierarchicalState / push_state 示例。之前的主体调用了两次
exit(),并忽略了恢复消息。
必须使用以下路径:
- 层级结构 / 物理输入转发:hsm_hierarchical_base.gd
- 压入 / 弹出并使用
enter({"is_resume": true}):hsm_pushdown_stack.gd - 非法转换拦截:hsm_transition_guard.gd
- 上下文载荷:hsm_state_context.gd
下推栈约定(来自脚本 — 单次退出,恢复消息):
# See hsm_pushdown_stack.gd — do not reimplement
func push_state(state_path: String, msg: Dictionary = {}) -> void: ...
func pop_state() -> void:
# old.exit(); stack.back().enter({"is_resume": true})
pass
专家级状态机模式
1. HSM 可视化工具(调试工具)
使用专用的 Control 节点和 _draw(),在视口中可视化当前状态栈 / 层级结构,以便立即调试 [3, 11]。
class_name HSMVisualizer extends Control
@export var state_machine: Node
func _draw() -> void:
var font := ThemeDB.fallback_font
var pos := Vector2(20, 20)
# Recursively draw active state names...
draw_string(font, pos, "Active: " + state_machine.current_state.name)
2. 基于状态的音频(解耦)
避免在状态的 enter() 方法中硬编码 audio.play()。使用监听 state_changed 的同步器,将状态名称映射到 AudioStream 资源 [12, 13]。
class_name StateAudioSyncer extends Node
@export var state_machine: Node
@export var audio_map: Dictionary # { "Jump": preload("jump.wav") }
func _ready() -> void:
state_machine.state_changed.connect(_on_state_changed)
func _on_state_changed(_old, new_state: Node):
if audio_map.has(new_state.name):
$AudioPlayer.stream = audio_map[new_state.name]
$AudioPlayer.play()
3. 转换成本(效用 AI)
允许状态根据上下文评估自身的“权重”。StateMachine 会轮询同级状态的成本,并转换到成本最低的行为 [17, 18]。
# CostState.gd (Base)
func get_cost(context: Dictionary) -> float:
return 10.0 # Default weight
# UtilityStateMachine.gd
func _physics_process(_d: float) -> void:
var best_state: Node = current_state
var low_cost: float = INF
for child in get_children():
var cost = child.get_cost(context)
if cost < low_cost:
low_cost = cost
best_state = child
if best_state != current_state:
transition_to(best_state.name)
深入配方(按需查看)
LLM 不知情规则:如果通用 Agent 在阅读前不会知道某项内容,就将其放在这里或
scripts/中 — 切勿删除,只能移动。
| 主题 | 参考资料 |
|---|---|
| 状态约定 + 路由 | hsm-implementation-cookbook.md |
参考资料
渐进式披露:仅在研究特定 API 时打开官方文档链接;在路由到相关领域时加载相关技能 — 不要预加载整个知识体系。
官方文档
- 使用信号 — 通过
state_changed/ 转换扇出驱动流程,让监听器(动画、音频、AI)与进入/退出逻辑保持解耦。 - 场景组织 — 子节点拥有状态,并采用信号向上发送、调用向下传递的方式,让状态机负责协调,同时避免兄弟节点之间的紧密耦合。
- 什么是 Godot 类 — 对于分层 AI 行为,优先使用组合式状态节点和
class_name,而不是深层继承树。 - 空闲处理与物理处理 — 说明为何 HSM 必须在每个时钟周期将
_physics_process/_process转发给当前活动子状态(或层级)。 - 使用 SceneTree — 使用
call_deferred进行状态转换,避免在enter()中调用transition_to()时发生重入崩溃。 - Godot 通知 — 说明相对于
_ready和父节点缓存,安全连接初始enter()的时机。 - 资源 — 使用数据驱动的状态定义(
.tres)构建模块化 AI,无需将脚本嵌入每个角色。 - 使用 AnimationTree — 当游戏 HSM 状态映射到混合/状态机图时,说明逻辑如何流转到 AnimationTree。
- AnimationNodeStateMachinePlayback — 动画同步器使用的
travel()/start()API,可与 HSM 状态名称绑定。 - Node — 状态节点作为场景树成员所继承的子节点查找、处理模式和生命周期钩子。
- InputEvent — 父节点转发给活动状态
handle_input的类型化事件。 - Timer — 通过触发状态转换信号的一次性计时器,实现有限时长状态(眩晕、冲刺)。
相关技能
前置要求
- godot-project-foundations — 每个 HSM 根场景和子状态场景所依赖的场景所有权与项目布局约定。
- godot-gdscript-mastery — 守卫条件、延迟状态转换和上下文对象所需的 class_name、类型化 Dictionaries/载荷和 Callables。
- godot-signal-architecture — 通过向上发送信号传递状态转换事件,避免状态既发送又监听自身而形成循环图。
配套技能
- godot-composition — 将 HSM / VSM 作为 StateComponent 放在组合根节点下,而不是让 Actor 脚本变得臃肿。
- godot-input-handling — 由感知层采样;状态通过 handle_input 接收方向 / 动作,而不是轮询全局变量。
- godot-characterbody-2d — 移动状态通过 context 传入的 Actor 调用 move_and_slide / velocity API。
- godot-animation-tree-mastery — 混合树和 AnimationNodeStateMachine 图,HSM 同步器会按状态名称在其中切换。
- godot-resource-data-patterns — 可调节的状态 Resource(速度、眩晕时长、AI 权重)与运行时 Node 生命周期分离。
- godot-2d-animation — 当无需完整 AnimationTree、较轻量的同步路径即可满足需求时,使用 Sprite / AnimationPlayer 进行表现。
下游 / 使用方
- godot-combat-system — 受击硬直、攻击前摇和死亡状态叠层都是格斗角色中典型的下推式 / HSM 使用场景。
- godot-ability-system — 施法、引导和冷却阶段可自然映射为带守卫条件的转换和定时状态。
- godot-turn-system — 回合阶段和中断叠层可复用下推式 / 并发状态机编排模式。
- godot-dialogue-system — 过场动画和对话叠层会压入游戏状态之上,且弹出时必须保留上下文。
主索引
- godot-master — 库路由器和镜像模块入口;需要了解哪个领域技能负责跨领域架构问题时,请打开此项。