跳转到内容

组件操作

实体通过添加组件来获得功能。本节详细介绍所有组件操作 API。

添加已创建的组件实例:

import { Component, ECSComponent } from '@esengine/ecs-framework';
@ECSComponent('Position')
class Position extends Component {
x: number = 0;
y: number = 0;
constructor(x: number = 0, y: number = 0) {
super();
this.x = x;
this.y = y;
}
}
const player = scene.createEntity("Player");
const position = new Position(100, 200);
player.addComponent(position);

直接传入组件类型和构造参数,由实体创建组件实例(推荐方式):

// 创建并添加组件
const position = player.createComponent(Position, 100, 200);
const health = player.createComponent(Health, 150);
// 等价于
// const position = new Position(100, 200);
// player.addComponent(position);

批量添加多个组件:

const components = player.addComponents([
new Position(100, 200),
new Health(150),
new Velocity(0, 0)
]);

获取指定类型的组件:

// 返回 Position | null
const position = player.getComponent(Position);
if (position) {
position.x += 10;
position.y += 20;
}

检查实体是否拥有指定类型的组件:

if (player.hasComponent(Position)) {
const position = player.getComponent(Position)!;
// 使用 ! 因为我们已经确认存在
}

获取指定类型的所有组件(支持同类型多组件场景):

const allHealthComponents = player.getComponents(Health);

支持继承查找的组件获取,使用 instanceof 检查:

// 查找 CompositeNodeComponent 或其任意子类
const composite = entity.getComponentByType(CompositeNodeComponent);
if (composite) {
// composite 可能是 SequenceNode, SelectorNode 等
}

getComponent() 的区别:

方法查找方式性能使用场景
getComponent精确类型匹配(位掩码)知道确切类型
getComponentByTypeinstanceof 检查较低需要支持继承

获取或创建组件,如果不存在则自动创建:

// 确保实体拥有 Position 组件
const position = player.getOrCreateComponent(Position, 0, 0);
position.x = 100;
// 如果已存在,返回现有组件
// 如果不存在,使用 (0, 0) 参数创建新组件

获取实体的所有组件(只读):

const allComponents = player.components; // readonly Component[]
allComponents.forEach(component => {
console.log(component.constructor.name);
});

通过组件实例移除:

const healthComponent = player.getComponent(Health);
if (healthComponent) {
player.removeComponent(healthComponent);
}

通过组件类型移除:

const removedHealth = player.removeComponentByType(Health);
if (removedHealth) {
console.log("健康组件已被移除");
}

批量移除多种组件类型:

const removedComponents = player.removeComponentsByTypes([
Position,
Health,
Velocity
]);

移除所有组件:

player.removeAllComponents();

标记组件为已修改,用于帧级变更检测系统:

const pos = entity.getComponent(Position)!;
pos.x = 100;
entity.markDirty(pos);
// 或标记多个组件
const vel = entity.getComponent(Velocity)!;
entity.markDirty(pos, vel);

配合响应式查询使用:

// 在系统中查询本帧修改过的组件
const changedQuery = scene.createReactiveQuery({
all: [Position],
changed: [Position] // 只匹配本帧修改过的
});
for (const entity of changedQuery.getEntities()) {
// 处理位置变化的实体
}

每个实体维护一个组件位掩码,用于高效的 hasComponent 检查:

// 获取组件掩码(内部使用)
const mask = entity.componentMask;
import { Component, ECSComponent, Scene } from '@esengine/ecs-framework';
@ECSComponent('Position')
class Position extends Component {
constructor(public x = 0, public y = 0) { super(); }
}
@ECSComponent('Health')
class Health extends Component {
constructor(public current = 100, public max = 100) { super(); }
}
// 创建实体并添加组件
const player = scene.createEntity("Player");
player.createComponent(Position, 100, 200);
player.createComponent(Health, 150, 150);
// 获取并修改组件
const position = player.getComponent(Position);
if (position) {
position.x += 10;
player.markDirty(position);
}
// 获取或创建组件
const velocity = player.getOrCreateComponent(Velocity, 0, 0);
// 检查组件存在
if (player.hasComponent(Health)) {
const health = player.getComponent(Health)!;
health.current -= 10;
}
// 移除组件
player.removeComponentByType(Velocity);
// 列出所有组件
console.log(player.components.map(c => c.constructor.name));