SuperAPI AI 工具集

godot-composition

编程与开发

查看项目

更新于 10-15 18:28

技能介绍

用途

godot-composition 是一套 Godot 游戏架构规范技能,用于以“组合模式(Entity-Component)”构建可扩展的游戏,例如 RPG、平台跳跃和射击游戏。它适用于设计玩家控制器、NPC、敌人、武器或复杂玩法系统,并强制游戏实体采用“Has-A(拥有)”关系,而非继承式的“Is-a”。触发关键词包括 Entity-Component、ECS、Gameplay、Actors、NPCs、Enemies、Weapons、Hitboxes、Game Loop、Level Design。

核心哲学

该技能强制“组合优于继承”。在 Godot 中,节点本身就是组件。一个复杂实体(如玩家)只是一个编排者(Orchestrator),负责管理多个专职的工作节点(组件)。

黄金规则:

  1. 单一职责:一个脚本只做一件事。
  2. 封装:组件是“自私的”,只处理自身内部逻辑,不知道谁拥有它。
  3. 编排者:根脚本(如 player.gd)不做任何逻辑,只管理状态并在组件之间传递数据。
  4. 解耦:组件之间通过信号(向上)和方法(向下)通信。

决策树:组合 vs Autoload vs 继承

情况 选择
玩法实体行为(HP、命中盒、移动、交互) 组合——子组件 + 编排者(composition_root_init.gd)
跨场景服务(音频总线、存档、网络、经济账本) Autoload——不是挂在玩家上的组件
真正的 is-a 引擎特化(带共享生命周期的自定义 Control/Node) 继承例外——罕见;绝不用于“加一把枪”或“加 HP”

主要能力(可用脚本)

  • health_component.gd:管理任意实体的生命周期、伤害逻辑与死亡信号。
  • hit_box_component.gd:基于 Area 的组件,用于拦截伤害并委托给 HealthComponent。
  • hurt_box_component.gd:基于 Area 的组件,专门对 HitBoxComponent 造成伤害。
  • velocity_component.gd:封装移动与加速度逻辑,可在玩家和敌人之间复用。
  • interaction_component.gd:解耦的交互处理器,通过注入 Callable 逻辑实现上下文感知动作。
  • follower_component.gd:解耦的追踪逻辑,通过注入 NodePath 实现平滑跟随。
  • state_component_vsm.gd:基于组件的状态机模式,用子节点表示各个状态。
  • status_effect_component.gd:通过将效果场景作为子节点堆叠,管理临时增益/减益。
  • visual_sync_component.gd:将逻辑状态(速度/方向)与视觉表现(精灵翻转)分离。
  • composition_root_init.gd:必读的编排者接线脚本,通过带类型的 @export(Inspector / 场景中的 %UniqueNames)完成连接;绝不使用 $ 或 get_node 查找组件。

使用方式

连接策略:带类型的导出

不要依赖树顺序,使用 @export 加静态类型进行显式依赖注入。示例:

# 编排者(如 player.gd)
class_name Player extends CharacterBody3D

# 依赖注入:在背包里定义“插槽”
@export var health_component: HealthComponent
@export var movement_component: MovementComponent
@export var input_component: InputComponent

# 使用场景唯一名(%)在编辑器中自动赋值
# 或在 Inspector 中拖放。

组件思维

组件必须定义 class_name 才能被识别为类型。标准组件模板:

class_name MyComponent extends Node 
# 逻辑用 Node,需要位置则用 Node3D/2D

@export var stats: Resource # 组件可以持有自己的数据
signal happened_something(value)

func _ready() -> void:
    _validate_dependencies()

func _validate_dependencies() -> void:
    # 依赖校验:开发期设置错误时尽早失败
    # 注意:assert() 在发布构建中会被剥离。
    assert(stats != null, "Stats Resource missing on %s" % name)

func do_logic(delta: float) -> void:
    # 执行具体任务
    pass

标准组件

内联的输入/移动/生命值配方已移除。强制要求:从 composition_root_init.gd 开始,然后加载匹配脚本:

  • 生命/死亡:health_component.gd
  • 伤害区域:hit_box_component.gd、hurt_box_component.gd
  • 运动:velocity_component.gd
  • 交互/跟随/VFX 同步:interaction_component.gd、follower_component.gd、visual_sync_component.gd
  • 状态/状态效果:state_component_vsm.gd、status_effect_component.gd

带类型的 @export 接线方式见上文“实现标准”。

专家组合模式

1. 状态-组件模式(FSM)

将复杂行为封装为充当状态的子节点,父 StateComponent 将生命周期调用委托给当前激活的子节点。强制要求阅读 state_component_vsm.gd,不要内联粘贴状态机。更深入的 VSM / 分层 FSM 请打开 godot-state-machine-advanced。

2. 组件注册表(O(1) 查找)

避免为兄弟通信进行缓慢的树遍历,在 ready 时用字典按名称或分组编目子节点:

var _components: Dictionary = {}

func _ready() -> void:
    for child in get_children():
        _components[child.name] = child
        for group in child.get_groups():
            _components[group] = child

func get_comp(key: StringName) -> Node:
    return _components.get(key)

3. 依赖校验

用 @export 断言快速失败,而不是 get_node_or_null 路径(树重排时路径会失效):

@export var health_component: HealthComponent
@export var input_component: InputComponent

func _ready() -> void:
    assert(health_component != null, "Missing HealthComponent export!")
    assert(input_component != null, "Missing InputComponent export!")

输入/移动/生命值编排者配方与注册表深度,强制参考 orchestrator-recipes.md。当 composition_root_init.gd 加一个组件脚本已足够时,不要加载该文件。

组合中绝不要做的事

  • 绝不使用深层继承链(如 Player > Entity > LivingThing > Node)——会产生难以重构的脆弱“上帝类”。
  • 绝不用 get_node() 或 $ 查找组件——场景树重排时会失效,始终用 @export 或 %UniqueNames。
  • 绝不让组件直接引用其父脚本——这会使组件无法复用,应使用信号或依赖注入。
  • 绝不把输入、物理和游戏逻辑混在一个脚本中——违反单一职责,应拆分为专职组件。
  • 绝不创建需要特定 SceneTree 结构的组件——组件应“自私”,只关心自身属性和直接子节点。
  • 绝不用继承来“添加功能”——若想让敌人射击,添加 ShootingComponent,而不是让它继承 ShooterEnemy。
  • 绝不硬编码组件依赖——若 CombatComponent 需要 HealthComponent,在 _ready() 中查找或由父级注入。
  • 绝不把 Godot 节点当作纯数据——节点提供生命周期(_process)和信号;若只需要数据,使用 Resource。
  • 绝不忽略组件中的节点生命周期——对无论父级状态如何都必须发生的设置/清理,使用 _enter_tree() 和 _exit_tree()。
  • 绝不隐藏组件的访问点——暴露 NodePath 或 Callable 属性,让父级能在 Inspector 中接线。

性能说明

节点是轻量的。不要害怕每个实体增加 10-20 个节点。组合带来的组织收益远超 Node 实例可忽略的内存开销。

适用场景与限制

适用场景:Godot 中需要构建可扩展玩法实体的项目,尤其是玩家控制器、NPC、敌人、武器、命中盒、游戏循环与关卡设计相关的系统。

限制与注意:该技能是一套架构规范与脚本集合,不提供具体游戏成品;assert() 在发布构建中会被剥离,因此依赖校验只在开发期生效;组件不应依赖特定场景树结构,也不应直接引用父脚本。关于收费、价格、平台支持范围等信息,资料中暂未提供。