Системы
Аспект сцены: игровая логика, у которой нет одного узла, где жить — маппинг ввода, пулы FX,
HUD, игровой режим, телеметрия. У системы ровно тот же жизненный цикл, что у
аспекта (onAttach / onDetach / onReconfigure, updateBefore / updateFixed /
update, updateOrder / static after, события), и прикрепляется она к сцене, а не к узлу:
scene.system(Fx) → scene.fx. Используй её там, где иначе написал бы класс «game» с ручным
tick(), вызывающим всё по порядку.
Обзор
class Controls extends System<'controls'> {
moveX = 0; moveY = 0; fire = false
updateBefore() { // РАНО: опрашиваем до шага симуляции
this.moveX = (Input.key('KeyD') ? 1 : 0) - (Input.key('KeyA') ? 1 : 0)
this.moveY = (Input.key('KeyW') ? 1 : 0) - (Input.key('KeyS') ? 1 : 0)
this.fire = Input.key('MouseLeft')
}
}
class Hud extends System<'hud', Scene, { announce: (text: string) => void }> {
static after = [Controls]
private banner = UIText('').style({ fontSize: 30, color: '#ffffff' })
onAttach() { this.scene.setContent([UIWidget(this.banner).style({ left: '50%', top: '20%' })]) }
announce(text: string) { this.banner.text = text; this.emit('announce', text) }
update(dt: number) { this.banner.style.opacity = this.scene.get(Controls)!.fire ? 0.5 : 1 }
}
const scene = new Scene().system(Controls).system(Hud)
scene.open()
scene.hud.on('announce', (t) => console.log('[hud]', t))
scene.hud.announce('ROUND 1')Прикрепление, доступ, открепление
scene.system(Class, opts?): scene & { name: instance } // прикрепить + сконфигурировать (или переконфигурировать)
scene.get(Class): instance | undefined // безопасный доступ
scene.has(Class): boolean // проверка существования И type guard
scene.removeSystem(Class): scene // открепить (выполняет onDetach); цепочечный
scene.destroy(): void // каждая система открепляется, затем сцена закрывается
Aspect.all(Class): readonly instance[] // системы регистрируются как аспектыТе же правила, что у node.aspect(): имя аксессора берётся из первого generic-параметра, opts
присваиваются до onAttach, второй system(Class, opts) переконфигурирует вместо повторного
прикрепления, а аксессор типизирован на результате цепочки (const scene = new Scene().system(Hud) →
scene.hud). destroy() открепляет системы в порядке «последняя прикреплённая — первая», пока
сцена ещё существует; Scene2D затем уничтожается и нативно, 3D Scene закрывается, а её узлы
остаются твоими.
Как написать систему
class Fx extends System<'fx'> { // <имя аксессора, вид сцены = Scene, события = {}>
private sparks!: Particles
onAttach() { // this.scene — сцена, к которой прикрепили
this.sparks = new Particles({ blend: 'add', rate: 0, lifetime: 0.4, size: 0.05 })
this.scene.add(this.sparks)
}
onDetach() { this.sparks.destroy() }
impact(p: Vec3) { this.sparks.position = p; this.sparks.spawn(20) }
}this.scene(иthis.node— тот же объект) — это сцена, типизированная вторым generic:System<'fx'>нацелен на 3DScene,System<'fx', Scene2D>— на 2D. Прикрепление 2D-системы к 3D-сцене (или наоборот) — ошибка компиляции.- Внутри системы
this.sceneтипизирован как простой вид сцены, без аксессоров других систем: доставай их черезthis.scene.get(Controls)!. - Системы создаёт
scene.system(), никогда неnew— конструктора нет; инициализируй вonAttach. - Порядок между системами и аспектами — один список на фазу:
static after = [Controls]на аспекте может называть систему и наоборот (см. aspects.md).
Что относится к системе, а что к аспекту
| Аспект (на узле) | Система (на сцене) | |
|---|---|---|
| Владеет | поведением / состоянием одного узла | состоянием всей сцены, пулами, сервисами |
| Примеры | Health, ExplosiveBarrel, PlayerController, CameraFollow |
Controls, Fx, Hud, GameMode, Spawner |
| Находится через | node.get(Ctor), Aspect.all(Ctor), use() в файле сцены |
scene.get(Ctor), scene.fx |
| Время жизни | до removeAspect / node.destroy() |
до removeSystem / scene.destroy() |
Не навешивай общесценное на узел-пустышку («пустой с аспектом Loop»): для этого и есть система. Но и не превращай состояние отдельного объекта в систему — hp бочки живёт на бочке.
Смотрите также
- Аспекты — фазы, порядок, события (всё общее с системами)
- Time — пауза / масштаб времени
- Архитектура проекта — целая игра из систем и аспектов