godot-coding-standards
Godot 4.x GDScript 编码规范。当编写、审查、修改 Godot 代码时使用。适用于:GDScript 脚本、场景创建、组件设计、Resource 类、信号连接、节点组织、类型注解、命名规范、性能优化。触发词:godot, gdscript, 组件, 信号, export, 场景。
SKILL.md.claude/skills/godot-coding-standards
GitHubGodot 4.x 核心架构原则
设计原则
- 通用性 —
@export配置化,组件跨场景复用,不依赖特定父节点 - 模块化 — 单一职责,组件组合复杂行为,信号松耦合
- 可复用 — Resource 存储配置(Damage, SkillData),清晰接口,private
_前缀 - 简洁 — 不过度设计,不为未来需求预设,代码自解释
- 继承+钩子 — 通用逻辑在基类,提供可重写钩子,子类只重写必要方法
编辑器配置优先
- Node 派生对象在编辑器创建配置,代码只控制运行时参数
- 动态生成:
preload("*.tscn").instantiate(),不new()+add_child() - 编辑器负责: 节点层级、属性默认值、信号连接、AnimationTree 节点
- 代码负责:
set()参数驱动、travel()状态切换、条件判断
场景模板(Scene Template)原则 — 骨架 vs 内容
核心原则:模板只做骨架,不做内容。被多个实例继承的 .tscn(如 AgentAIBase.tscn、PlayerBase.tscn)必须只包含"所有继承者都需要的结构",不预设任何实例特有的视觉、数值、shape、动画数据。
骨架(属于模板) vs 内容(属于实例)
| 类别 | 骨架(模板提供) | 内容(实例自加) |
|---|---|---|
| 节点结构 | CharacterBody2D 根、HurtBox/HitBox/HealthComponent/HealthBar/AnimationPlayer/AIController/StateMachine 等公共组件节点 |
AnimatedSprite2D / Sprite2D 等视觉节点(每个 boss 自己选) |
| 状态机 | Stock states:Idle/Chase/Hit/Death/Dispatcher/GenericAttack/Combo(无 boss 配置、所有 boss 都用) |
Boss 特殊 states(如 BK 的 Approach、DS2 的 Counter/Defend/Roll/Stun) |
| Shape | CollisionShape2D 节点存在但 shape 留空 |
shape 大小、形状由 boss 自填 |
| 动画 | AnimationPlayer 节点存在、libraries/ 留空 |
AnimationLibrary 资源、track 内容 |
| 数值 | 字段定义、@export 默认值 = 0/null |
max_health、base_move_speed 等具体数值 override |
Leakage 反 pattern(必须避免)
模板里任何一处指向具体子节点或假设具体内容,都会污染所有继承者:
- 占位视觉节点(如模板放
Sprite2D,但 boss 用AnimatedSprite2D)- 后果:实例被迫"忽略继承的节点 + 加 sibling 替代节点"。继承场景无法删除继承来的节点,只能 override 字段。
- 修法:模板不预放视觉节点,由 boss 实例自己 add。
- 默认 shape(如
RectangleShape2Dsize=Vector2(81, 80))- 后果:boss 忘记 override 时仍能编译,但 hitbox 大小荒谬。
- 修法:shape 节点存在但
shape = null,boss 必须显式 assign。
- RESET 动画引用具体子节点(如
Sprite2D:modulatetrack)- 后果:boss 改了视觉节点名/类型,模板的 RESET 失效。
- 修法:模板的 AnimationLibrary 留空,让 boss 在自己的库里定义 RESET。
- boss-specific 状态进入模板(如把
Counter加进 AgentAIBase)- 后果:所有不需要 Counter 的 boss 都背着 dead code。
- 修法:保持模板纯净 —— 加节点前问"所有继承者都需要吗?"否则放实例。
实操规则
- 添加节点入模板前自问:"所有继承者都需要它吗?" 否则放实例。
- shape / animation library / sprite frames 等数据资源不预填,留空。
- 节点必须存在(structural)但内容必须空(data-empty)—— 例:
CollisionShape2D节点在,shape字段空。 - 模板升级(加新事件、新组件字段)时所有继承者自动同步;这是接受继承复杂度的根本回报。
- 实例需要的特殊功能(boss-specific buff、特殊状态、特效节点)永远在实例内,不上推到模板。
状态机 + AnimationTree 规范
统一 BlendTree:
locomotion → loco_timescale → control_blend[0]
control_sm → ctrl_timescale → control_blend[1]
control_blend → output
- 状态继承 BaseState,用 helper:
set_locomotion(),enter_control_state(),exit_control_state() - 优先级三层:
BEHAVIOR(0) < REACTION(1) < CONTROL(2) exit()必须断开animation_finished信号 + 停止 Timer- locomotion 两模式: BlendSpace2D (
set_locomotion(Vector2)) / StateMachine (set_locomotion_state())
架构检查要点
@export配置化?跨场景复用?- 单一职责?信号解耦?
- 清晰接口?Resource 正确使用?
- 基类钩子?子类最小化重写?
- 编辑器配置节点?不在代码中
new()Node? - 状态继承 BaseState?用 helper 不直接操作 AnimationTree?
- exit() 断开信号+停止 Timer?
- 场景模板纯骨架? 模板里有无占位视觉节点 / 默认 shape / boss-specific state / 引用具体子节点的 RESET 动画?(任一项即 leakage,必须迁回实例)