Skip to content

Commit

Permalink
feat: static System priority (#3207)
Browse files Browse the repository at this point in the history
Closes #3102

## Changes:

- Refactored `System.priority` to be static
- Updated `priority` in all systems
- Updated priority sort in `SystemManager`
  • Loading branch information
Autsider666 authored Sep 20, 2024
1 parent 81495b2 commit c6315eb
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Breaking Changes

- `System.priority` is refactored to be static.
- `ex.Timer` now only takes the option bag constructor
- `PreDrawEvent`, `PostDrawEvent`, `PreTransformDrawEvent`, `PostTransformDrawEvent`, `PreUpdateEvent`, `PostUpdateEvent` now use `elapsedMs` instead of `delta` for the elapsed milliseconds between the last frame.460696
- `Trigger` API has been slightly changed:
Expand Down
3 changes: 2 additions & 1 deletion src/engine/Actions/ActionsSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { System, SystemType } from '../EntityComponentSystem/System';
import { ActionsComponent } from './ActionsComponent';

export class ActionsSystem extends System {
static priority = SystemPriority.Higher;

systemType = SystemType.Update;
priority = SystemPriority.Higher;
private _actions: ActionsComponent[] = [];
query: Query<typeof ActionsComponent>;

Expand Down
3 changes: 2 additions & 1 deletion src/engine/Collision/CollisionSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ import { SeparatingAxis } from './Colliders/SeparatingAxis';
import { MotionSystem } from './MotionSystem';
import { Pair } from './Detection/Pair';
export class CollisionSystem extends System {
static priority = SystemPriority.Higher;

public systemType = SystemType.Update;
public priority = SystemPriority.Higher;
public query: Query<ComponentCtor<TransformComponent> | ComponentCtor<MotionComponent> | ComponentCtor<ColliderComponent>>;

private _engine: Engine;
Expand Down
3 changes: 2 additions & 1 deletion src/engine/Collision/MotionSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { EulerIntegrator } from './Integrator';
import { PhysicsWorld } from './PhysicsWorld';

export class MotionSystem extends System {
static priority = SystemPriority.Higher;

public systemType = SystemType.Update;
public priority = SystemPriority.Higher;
private _physicsConfigDirty = false;
query: Query<typeof TransformComponent | typeof MotionComponent>;
constructor(
Expand Down
3 changes: 2 additions & 1 deletion src/engine/Debug/DebugSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ import { CoordPlane } from '../Math/coord-plane';
import { Debug } from '../Graphics/Debug';

export class DebugSystem extends System {
static priority = SystemPriority.Lowest;

public readonly systemType = SystemType.Draw;
public priority = SystemPriority.Lowest;
private _graphicsContext: ExcaliburGraphicsContext;
private _collisionSystem: CollisionSystem;
private _camera: Camera;
Expand Down
2 changes: 1 addition & 1 deletion src/engine/EntityComponentSystem/System.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export abstract class System {
* For a system to execute before all other a lower priority value (-1 for example) must be set.
* For a system to execute after all other a higher priority value (10 for example) must be set.
*/
public priority: number = SystemPriority.Average;
public static priority: number = SystemPriority.Average;

/**
* Optionally specify an initialize handler
Expand Down
2 changes: 1 addition & 1 deletion src/engine/EntityComponentSystem/SystemManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class SystemManager {
}

this.systems.push(system);
this.systems.sort((a, b) => a.priority - b.priority);
this.systems.sort((a, b) => (a.constructor as typeof System).priority - (b.constructor as typeof System).priority);
// If systems are added and the manager has already been init'd
// then immediately init the system
if (this.initialized && system.initialize) {
Expand Down
3 changes: 2 additions & 1 deletion src/engine/Graphics/GraphicsSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ import { blendTransform } from './TransformInterpolation';
import { Graphic } from './Graphic';

export class GraphicsSystem extends System {
static priority = SystemPriority.Average;

public readonly systemType = SystemType.Draw;
public priority = SystemPriority.Average;
private _token = 0;
// Set in the initialize
private _graphicsContext!: ExcaliburGraphicsContext;
Expand Down
3 changes: 2 additions & 1 deletion src/engine/Graphics/OffscreenSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import { BoundingBox } from '../Collision/BoundingBox';
import { Query, SystemPriority, World } from '../EntityComponentSystem';

export class OffscreenSystem extends System {
static priority: number = SystemPriority.Higher;

public systemType = SystemType.Draw;
priority: number = SystemPriority.Higher;
private _camera!: Camera;
private _screen!: Screen;
private _worldBounds!: BoundingBox;
Expand Down
3 changes: 2 additions & 1 deletion src/engine/Input/PointerSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import { SparseHashGrid } from '../Collision/Detection/SparseHashGrid';
* the {@apilink Collider}'s shape for pointer events.
*/
export class PointerSystem extends System {
static priority = SystemPriority.Higher;

public readonly systemType = SystemType.Update;
public priority = SystemPriority.Higher;

private _engine: Engine;
private _receivers: PointerEventReceiver[];
Expand Down
3 changes: 2 additions & 1 deletion src/engine/TileMap/IsometricEntitySystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { IsometricEntityComponent } from './IsometricEntityComponent';
import { Query, SystemPriority, World } from '../EntityComponentSystem';

export class IsometricEntitySystem extends System {
static priority: number = SystemPriority.Lower;

public readonly systemType = SystemType.Update;
priority: number = SystemPriority.Lower;
query: Query<typeof TransformComponent | typeof IsometricEntityComponent>;
constructor(public world: World) {
super();
Expand Down
60 changes: 47 additions & 13 deletions src/spec/SystemManagerSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,45 @@ class FakeComponentA extends ex.Component {}
class FakeComponentB extends ex.Component {}
class FakeComponentC extends ex.Component {}

class FakeSystem extends ex.System {
class FakeSystemPriority1 extends ex.System {
static priority = 1;
query: ex.Query<ex.ComponentCtor<ex.Component>>;
constructor(
public world: ex.World,
public name: string,
public types: ex.ComponentCtor[],
public systemType: ex.SystemType
) {
super();
this.query = this.world.query(types);
}
update(elapsedMs: number): void {
// fake
}
}

class FakeSystemPriority2 extends ex.System {
static priority = 2;
query: ex.Query<ex.ComponentCtor<ex.Component>>;
constructor(
public world: ex.World,
public name: string,
public types: ex.ComponentCtor[],
public systemType: ex.SystemType
) {
super();
this.query = this.world.query(types);
}
update(elapsedMs: number): void {
// fake
}
}

class FakeSystemPriority3 extends ex.System {
static priority = 3;
query: ex.Query<ex.ComponentCtor<ex.Component>>;
constructor(
public world: ex.World,
public priority: number,
public name: string,
public types: ex.ComponentCtor[],
public systemType: ex.SystemType
Expand All @@ -36,11 +70,11 @@ describe('A SystemManager', () => {
const sm = world.systemManager;

// Lower priority
const s3 = new FakeSystem(world, 2, 'System3', [FakeComponentC], SystemType.Update);
const s3 = new FakeSystemPriority2(world, 'System3', [FakeComponentC], SystemType.Update);
sm.addSystem(s3);
// Systems of equal priority should preserve order
const s1 = new FakeSystem(world, 1, 'System1', [FakeComponentA], SystemType.Update);
const s2 = new FakeSystem(world, 1, 'System2', [FakeComponentC, FakeComponentB], SystemType.Update);
const s1 = new FakeSystemPriority1(world, 'System1', [FakeComponentA], SystemType.Update);
const s2 = new FakeSystemPriority1(world, 'System2', [FakeComponentC, FakeComponentB], SystemType.Update);
sm.addSystem(s1);
sm.addSystem(s2);

Expand All @@ -52,11 +86,11 @@ describe('A SystemManager', () => {
const sm = world.systemManager;

// Lower priority
const s3 = new FakeSystem(world, 2, 'System3', [FakeComponentC], SystemType.Update);
const s3 = new FakeSystemPriority2(world, 'System3', [FakeComponentC], SystemType.Update);
sm.addSystem(s3);
// Systems of equal priority should preserve order
const s1 = new FakeSystem(world, 1, 'System1', [FakeComponentA], SystemType.Update);
const s2 = new FakeSystem(world, 1, 'System2', [FakeComponentC, FakeComponentB], SystemType.Update);
const s1 = new FakeSystemPriority1(world, 'System1', [FakeComponentA], SystemType.Update);
const s2 = new FakeSystemPriority1(world, 'System2', [FakeComponentC, FakeComponentB], SystemType.Update);
sm.addSystem(s1);
sm.addSystem(s2);

Expand All @@ -69,7 +103,7 @@ describe('A SystemManager', () => {
it('can update systems', () => {
const world = new ex.World(null);
const sm = world.systemManager;
const system = new FakeSystem(world, 2, 'System3', [FakeComponentC], SystemType.Update);
const system = new FakeSystemPriority2(world, 'System3', [FakeComponentC], SystemType.Update);
system.preupdate = () => {}; // eslint-disable-line @typescript-eslint/no-empty-function
system.postupdate = () => {}; // eslint-disable-line @typescript-eslint/no-empty-function
spyOn(system, 'preupdate');
Expand All @@ -87,7 +121,7 @@ describe('A SystemManager', () => {
const sm = world.systemManager;
const qm = world.queryManager;
const em = world.entityManager;
const system = new FakeSystem(world, 2, 'System3', [FakeComponentA, FakeComponentC], SystemType.Update);
const system = new FakeSystemPriority2(world, 'System3', [FakeComponentA, FakeComponentC], SystemType.Update);
spyOn(system, 'update').and.callThrough();
sm.addSystem(system);

Expand Down Expand Up @@ -119,10 +153,10 @@ describe('A SystemManager', () => {
const sm = world.systemManager;
const qm = world.queryManager;
const em = world.entityManager;
const system1 = new FakeSystem(world, 2, 'System1', [FakeComponentA, FakeComponentC], SystemType.Update);
const system1 = new FakeSystemPriority2(world, 'System1', [FakeComponentA, FakeComponentC], SystemType.Update);
spyOn(system1, 'update').and.callThrough();
sm.addSystem(system1);
const system2 = new FakeSystem(world, 2, 'System1', [FakeComponentA, FakeComponentC], SystemType.Draw);
const system2 = new FakeSystemPriority2(world, 'System1', [FakeComponentA, FakeComponentC], SystemType.Draw);
spyOn(system2, 'update').and.callThrough();
sm.addSystem(system2);

Expand All @@ -136,7 +170,7 @@ describe('A SystemManager', () => {
const world = new ex.World(null);
const sm = world.systemManager;
expect(() => {
sm.addSystem(new FakeSystem(world, 0, 'ErrorSystem', [], SystemType.Update));
sm.addSystem(new FakeSystemPriority1(world, 'ErrorSystem', [], SystemType.Update));
}).toThrow(new Error('Cannot create query without components'));
});
});

0 comments on commit c6315eb

Please sign in to comment.