组件
组件是挂在实体上的一小块纯数据结构。用 defineComponent 声明一个组件,给它一个
名字和默认值:
import { defineComponent } from 'esengine';
const Speed = defineComponent('Speed', { value: 200 });const Health = defineComponent('Health', { current: 100, max: 100 });默认值同时定义了组件的形状(字段与类型)和新实例的初始值。组件是纯数据——没有方法、 没有行为。行为存在于系统里。
字段的类型由默认值推断。数字、布尔、字符串如你所想,结构化形状会得到对应的编辑器 控件:
const Missile = defineComponent('Missile', { speed: 400, // number homing: true, // boolean targetTag: '', // string velocity: { x: 0, y: 0 }, // 向量——以 X/Y 一对编辑 tint: { r: 1, g: 1, b: 1, a: 1 }, // {r,g,b,a} 字段渲染成拾色器});标签——没有数据的组件
Section titled “标签——没有数据的组件”**标签(tag)**是零字段的标记组件,纯粹用于过滤——Player、Enemy、Frozen。
用 defineTag 声明,在查询里配合 .with() / .without() 使用:
import { defineTag, defineSystem, Query, Mut, Transform } from 'esengine';
const Player = defineTag('Player');const Frozen = defineTag('Frozen');
defineSystem([Query(Mut(Transform)).with(Player).without(Frozen)], (q) => { /* … */ });编辑器元数据
Section titled “编辑器元数据”第三个参数控制字段在编辑器 Details 面板里的呈现——范围、滑杆、单位、枚举:
const Turret = defineComponent('Turret', { range: 300, mode: 0,}, { fields: { range: { min: 0, max: 1000, slider: true, unit: 'px' }, mode: { enum: [{ label: 'Idle', value: 0 }, { label: 'Attack', value: 1 }] }, },});常用的 fields 选项:min / max / step、slider、unit、enum(下拉,
存储选项的整数值)、flags(位掩码多选)、tooltip。其他组件级元数据:
assetFields(把字段标记为资产引用,Details 渲染选择器、cook 会带上依赖)、
animatableFields(Sequencer 可打关键帧的字段
——默认为全部数字字段)、transient(永不存进场景——用于逐帧运行时状态),以及
replicatedFields(由联网的状态复制同步)。
SDK 自带约 30 个引擎组件,与你自己的组件一起查询——Transform、Sprite、
ShapeRenderer、Camera、Light2D、ParticleEmitter、SpineAnimation、
TilemapLayer、UI 组件族、物理碰撞体等等。各自在对应的子系统指南里有完整文档:
精灵与渲染、相机、
2D 光照、物理、
瓦片地图、UI。
系统通过查询拿到组件数据。当系统要写入某个组件时,把它包进 Mut(...),这样变更检测
和渲染器就知道这块数据被改动过:
Query(Mut(Transform), Speed)// Transform 会被写入;Speed 只读因为写入被跟踪,系统也能响应生命周期:Added(Comp) / Changed(Comp) 把查询收窄到
组件刚出现 / 刚变化的实体——完整的查询词汇见
系统。
在底层,一个组件是带 ES_COMPONENT / ES_PROPERTY 注解的 C++ 结构体;跨边界的内存
布局是生成的,因此 TypeScript 组件与 C++ 结构体始终保持一致。