组件
本页面为自动翻译,可能包含错误。如果发现问题,请通过“编辑此页面”链接帮助修正。
组件(component) 是一个普通的 Zig 结构体,通过选择加入编辑器发现机制。无需继承基类,也无需注册样板代码——只需一个标记即可。
将结构体标记为组件
pub const Health = struct {
pub const is_component = true;
max: f32 = 100.0,
current: f32 = 100.0,
};
pub const is_component = true;标记该结构体以供发现。将其设置为false可暂时退出而不删除结构体。- 编辑器解析真实的 Zig 源代码(而非正则表达式),因此无论格式、注释或条件编译如何,标记都能正常工作。
- 结构体必须是
pub的,且名称必须以大写字母开头。 - 组件类型名称在项目中必须唯一。重复名称会被报告,第二个定义将被忽略。
用户脚本存放在项目的 assets/ 文件夹中。添加或编辑脚本后,点击资源浏览器中的 刷新 以重新扫描。
检查器字段类型
检查器根据字段的 Zig 类型渲染控件:
| Zig 类型 | 检查器控件 |
|---|---|
f32 |
带拖动箭头的数字字段 |
i32 |
整数字段 |
bool |
复选框 |
engine.Vec3 |
带标签的三轴向量 |
engine.GameObjectRef |
拖放目标——从层级面板拖动节点或场景对象 |
engine.ComponentRef |
拖放目标——引用节点上的任意组件 |
engine.TypedAssetRef(.) |
资源选择器——从资源浏览器拖动或使用 ... 按钮 |
engine.AssetRef |
资源选择器——任意资源类型 |
[N]type(静态数组) |
可单独编辑的元素 |
[]const u8 |
文本字段 |
检查器跳过的字段:
- 私有字段(下划线前缀,如
_internal_state)。 - 没有默认值的字段(结构体定义中没有
= expr)。 comptime字段。*指针字段。
可用的生命周期钩子
所有钩子都是可选的。只实现你需要的即可。
| 钩子 | 签名 | 调用时机 |
|---|---|---|
awake |
fn(self) void |
组件首次加载时 |
enable |
fn(self) void |
节点变为活动状态(或组件被添加到活动节点)时 |
start |
fn(self) void |
场景开始运行时 |
update |
fn(self, time: engine.Time) void |
每帧——推荐使用 engine.Frame(见下文) |
disable |
fn(self) void |
节点变为非活动状态(或组件在销毁前被移除)时 |
destroy |
fn(self) void |
节点被销毁时 |
每个钩子也接受 frame: engine.Frame 作为第二个参数。当钩子接受 frame: engine.Frame 时,它可以接收输入、服务、场景树和实用工具:
pub fn update(self: *@This(), frame: engine.Frame) void {
if (frame.input.wasPressed("jump")) { /* ... */ }
}
这是推荐的签名,因为它提供了脚本所需的一切。
完整的节点生命周期
场景启动时,节点按自上而下的顺序激活。每个节点:
awake—— 按广度优先顺序(父节点先于子节点)在每个组件上调用。enable—— 按相同顺序调用。start—— 按相同顺序调用。
然后每帧:
update—— 每帧在每个组件上调用。
关闭时,节点按自下而上的顺序停用:
disable—— 在每个组件上调用。destroy—— 在每个组件上调用。
运行时添加的组件(在节点已激活后)会立即按顺序获得 awake → enable → start。
跨组件的更新顺序
在单个节点内,给定生命周期阶段的钩子按照源代码定义顺序触发——即字段和方法在结构体中出现的顺序。
跨节点之间,顺序由场景层级树决定:父节点先于子节点,同级节点按它们在层级中出现的顺序排列。该顺序在帧和保存之间保持稳定。要重新排序,在层级中拖动节点即可。
自定义更新顺序(例如"所有物理先于所有渲染")已计划但尚未实现。目前请使用树顺序。