插件与资源
一个 Estella 游戏就是由插件组合成的 App。每个子系统——物理、音频、瓦片地图、
粒子、UI 等等——都是一个插件,它注册自己的系统,并把运行时 API 暴露为一个资源。
取用子系统:Res(XxxAPI)
Section titled “取用子系统:Res(XxxAPI)”在系统里,把你需要的资源列进参数数组;回调会按同样的顺序收到它:
import { defineSystem, Res, Audio } from 'esengine';
defineSystem([Res(Audio)], (audio) => { audio.playSFX('assets/hit.wav');});每个子系统的命令式 API 都用同一种方式取用:
| 子系统 | 资源 | 指南 |
|---|---|---|
| 输入 | Res(Input) |
输入 |
| 音频 | Res(Audio) |
音频 |
| 资源 | Res(Assets) |
资源 |
| 瓦片地图 | Res(Tilemaps) |
瓦片地图 |
| 粒子 | Res(Particle) |
粒子 |
| 后处理 | Res(PostProcess) |
后处理 |
| 场景 | Res(SceneManager) |
场景 |
| 补间 | Res(Tween) |
动画 |
| 帧动画 | Res(SpriteAnimation) |
动画 |
| 动画机 | Res(AnimatorController) |
动画 |
| 计时器 | Res(TimerRes) |
脚本 |
| 时间轴 | Res(Timeline) |
时间轴 |
| 预制体 | Res(Prefabs) |
预制体 |
| 导航 / AI | Res(Nav) |
游戏 AI |
| 本地化 | Res(Localization) |
本地化 |
| 相机视图 | Res(CameraView) |
相机 |
| UI 事件 | Res(UIEvents) |
UI |
| 物理 | Res(Physics) —— 来自 esengine/physics |
物理 |
| Spine | Res(Spine) —— 来自 esengine/spine |
Spine |
物理和 Spine 是可选 side-module,按需加载,因此它们的 API 放在子路径上以保持基础
包精简;其余都在主 esengine 包里。上表的基础子系统都随标准 App 附带——无需接线。
有些子系统还按同一范式发布事件资源——内容是本帧事件、当帧读取的资源:
Res(PhysicsEvents)(碰撞接触)、Res(SpineEvents)(动画事件)、
Res(UIEvents)(控件的点击与输入)。
Res(X) 是读取;当系统要替换或改动资源的状态时用 ResMut(X)——与组件上的
Mut 是同一契约。
组件 vs 资源
Section titled “组件 vs 资源”- 组件是逐实体的数据。你(在编辑器里或用
Commands)把它挂到实体上,用Query遍历它。 - 资源是逐 App 的单例——共享状态与子系统 API——用
Res读取。
子系统 API 作用于某个实体,而这个实体来自一个 Query(或一次 spawn)。这是你在各专题
里会反复看到的写法:
import { defineSystem, Query, Res, SpriteAnimator, Tween, TweenTarget } from 'esengine';
defineSystem([Query(SpriteAnimator), Res(Tween)], (q, tween) => { for (const [entity] of q) { tween.to(entity, TweenTarget.PositionX, 0, 100, 1.0, {}); }});生成实体:Commands
Section titled “生成实体:Commands”要在系统里创建实体并挂组件,取一个 Commands():
import { defineSystem, Commands, Transform, Sprite } from 'esengine';
defineSystem([Commands()], (cmds) => { cmds.spawn() .insert(Transform, { position: { x: 0, y: 0, z: 0 } }) .insert(Sprite, { size: { x: 32, y: 32 } });});