跳转到内容

系统

系统包含游戏逻辑。它们通过参数声明需要的数据,ESEngine 自动注入。系统自动操作场景中所有匹配的实体

定义系统

import { defineSystem, Res, Time, Query, Mut, LocalTransform, Velocity } from 'esengine';
const movementSystem = defineSystem(
[Res(Time), Query(Mut(LocalTransform), Velocity)],
(time, query) => {
for (const [entity, transform, velocity] of query) {
transform.position.x += velocity.linear.x * time.delta;
transform.position.y += velocity.linear.y * time.delta;
}
}
);

此系统自动处理场景中所有同时拥有 LocalTransformVelocity 组件的实体。

defineSystem 接受两个参数:

  1. 参数列表QueryResResMutCommands 描述符的数组
  2. 函数 — 按相同顺序接收解析后的参数

注册系统

使用顶层函数注册系统:

import { addSystem, addStartupSystem, addSystemToSchedule, Schedule } from 'esengine';
addStartupSystem(setupSystem); // Schedule.Startup
addSystem(movementSystem); // Schedule.Update
addSystemToSchedule(Schedule.FixedUpdate, physicsSystem);

Schedule 类型

Schedule运行时机
Startup启动时运行一次
First每帧最先运行
PreUpdate每帧 Update 之前
Update每帧运行(主要游戏逻辑)
PostUpdate每帧 Update 之后
Last每帧最后运行
FixedPreUpdate固定间隔,FixedUpdate 之前
FixedUpdate固定间隔(物理)
FixedPostUpdate固定间隔,FixedUpdate 之后

系统参数

Commands

在运行时创建、修改和销毁实体:

import { Commands, Sprite, LocalTransform } from 'esengine';
defineSystem([Commands()], (cmds) => {
// 创建新实体并添加组件(可链式调用)
const bullet = cmds.spawn()
.insert(LocalTransform, { position: { x: 0, y: 0, z: 0 } })
.insert(Sprite, { size: { x: 8, y: 8 } })
.id();
// 修改已有实体
cmds.entity(bullet)
.insert(Velocity, { linear: { x: 100, y: 0 } })
.remove(Sprite);
// 销毁实体
cmds.despawn(bullet);
// 插入资源
cmds.insertResource(Score, { value: 0 });
});

Commands API

方法返回值说明
cmds.spawn()EntityCommands创建新实体,返回构建器
cmds.entity(entity)EntityCommands获取已有实体的构建器
cmds.despawn(entity)Commands将实体加入销毁队列
cmds.insertResource(res, value)Commands插入或覆盖资源

EntityCommands API

spawn()entity() 返回 EntityCommands 构建器,所有方法可链式调用:

方法返回值说明
.insert(component, data?)this添加或更新组件
.remove(component)this移除组件
.id()Entity获取实体 ID

Query

遍历具有特定组件的实体:

import { Query, Mut, LocalTransform, Sprite } from 'esengine';
defineSystem([Query(Mut(LocalTransform), Sprite)], (query) => {
for (const [entity, transform, sprite] of query) {
transform.position.x += 1;
}
});

详见查询

Res(只读资源)

import { Res, Time } from 'esengine';
defineSystem([Res(Time)], (time) => {
console.log(`Delta: ${time.delta}s`);
});

ResMut(可变资源)

import { ResMut } from 'esengine';
defineSystem([ResMut(GameState)], (state) => {
state.value.score += 10;
});

详见资源

组合参数

defineSystem(
[Commands(), Res(Time), Res(Input), Query(Mut(LocalTransform), Velocity)],
(cmds, time, input, query) => {
// 所有参数都可用
}
);

示例:玩家移动

定义 Speed 组件,在编辑器中挂载到玩家实体上,然后编写系统:

src/components/Speed.ts
import { defineComponent } from 'esengine';
export const Speed = defineComponent('Speed', { value: 200 });
src/systems/movement.ts
import { defineSystem, addSystem, Res, Time, Input, Query, Mut, LocalTransform } from 'esengine';
import { Speed } from '../components/Speed';
addSystem(defineSystem(
[Res(Time), Res(Input), Query(Mut(LocalTransform), Speed)],
(time, input, query) => {
for (const [entity, transform, speed] of query) {
if (input.isKeyDown('KeyD')) {
transform.position.x += speed.value * time.delta;
}
if (input.isKeyDown('KeyA')) {
transform.position.x -= speed.value * time.delta;
}
}
}
));

下一步

  • 查询 — 查询过滤器和迭代方法
  • 资源 — 全局单例数据