• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

excaliburjs / Excalibur / 14804036802

02 May 2025 09:58PM UTC coverage: 5.927% (-83.4%) from 89.28%
14804036802

Pull #3404

github

web-flow
Merge 5c103d7f8 into 0f2ccaeb2
Pull Request #3404: feat: added Graph module to Math

234 of 8383 branches covered (2.79%)

229 of 246 new or added lines in 1 file covered. (93.09%)

13145 existing lines in 208 files now uncovered.

934 of 15759 relevant lines covered (5.93%)

4.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/engine/EntityComponentSystem/EntityManager.ts
1
import { Entity } from './Entity';
2
import { World } from './World';
3
import { removeItemFromArray } from '../Util/Util';
4
import { Scene } from '../Scene';
5

6
// Add/Remove entities and components
7

8
export class EntityManager {
UNCOV
9
  public entities: Entity[] = [];
×
UNCOV
10
  public _entityIndex: { [entityId: string]: Entity } = {};
×
UNCOV
11
  private _childAddedHandlerMap = new Map<Entity, (entity: Entity) => void>();
×
UNCOV
12
  private _childRemovedHandlerMap = new Map<Entity, (entity: Entity) => void>();
×
13

UNCOV
14
  constructor(private _world: World) {}
×
15

16
  /**
17
   * Runs the entity lifecycle
18
   * @param scene
19
   * @param elapsed
20
   */
21
  public updateEntities(scene: Scene, elapsed: number) {
UNCOV
22
    for (let entityIndex = 0; entityIndex < this.entities.length; entityIndex++) {
×
UNCOV
23
      const entity = this.entities[entityIndex];
×
UNCOV
24
      entity.update(scene.engine, elapsed);
×
UNCOV
25
      if (!entity.isActive) {
×
UNCOV
26
        this.removeEntity(entity);
×
27
      }
28
    }
29
  }
30

31
  public findEntitiesForRemoval() {
UNCOV
32
    for (let entityIndex = 0; entityIndex < this.entities.length; entityIndex++) {
×
UNCOV
33
      const entity = this.entities[entityIndex];
×
UNCOV
34
      if (!entity.isActive) {
×
UNCOV
35
        this.removeEntity(entity);
×
36
      }
37
    }
38
  }
39

UNCOV
40
  private _createChildAddedHandler = () => (e: Entity) => {
×
UNCOV
41
    this.addEntity(e);
×
42
  };
43

UNCOV
44
  private _createChildRemovedHandler = () => (e: Entity) => {
×
UNCOV
45
    this.removeEntity(e, false);
×
46
  };
47

48
  /**
49
   * Adds an entity to be tracked by the EntityManager
50
   * @param entity
51
   */
52
  public addEntity(entity: Entity): void {
UNCOV
53
    entity.isActive = true;
×
UNCOV
54
    entity.scene = this._world.scene;
×
UNCOV
55
    if (entity && !this._entityIndex[entity.id]) {
×
UNCOV
56
      this._entityIndex[entity.id] = entity;
×
UNCOV
57
      this.entities.push(entity);
×
UNCOV
58
      this._world.queryManager.addEntity(entity);
×
59

60
      // if entity has children
UNCOV
61
      entity.children.forEach((c) => {
×
UNCOV
62
        c.scene = entity.scene;
×
UNCOV
63
        this.addEntity(c);
×
64
      });
UNCOV
65
      const childAdded = this._createChildAddedHandler();
×
UNCOV
66
      this._childAddedHandlerMap.set(entity, childAdded);
×
UNCOV
67
      const childRemoved = this._createChildRemovedHandler();
×
UNCOV
68
      this._childRemovedHandlerMap.set(entity, childRemoved);
×
UNCOV
69
      entity.childrenAdded$.subscribe(childAdded);
×
UNCOV
70
      entity.childrenRemoved$.subscribe(childRemoved);
×
71
    }
72
  }
73

74
  public removeEntity(entity: Entity, deferred?: boolean): void;
75
  public removeEntity(id: number, deferred?: boolean): void;
76
  public removeEntity(idOrEntity: number | Entity, deferred = true): void {
×
UNCOV
77
    let id = 0;
×
UNCOV
78
    if (idOrEntity instanceof Entity) {
×
UNCOV
79
      id = idOrEntity.id;
×
80
    } else {
UNCOV
81
      id = idOrEntity;
×
82
    }
UNCOV
83
    const entity = this._entityIndex[id];
×
UNCOV
84
    if (entity && entity.isActive) {
×
UNCOV
85
      entity.isActive = false;
×
86
    }
87

UNCOV
88
    if (entity && deferred) {
×
UNCOV
89
      this._entitiesToRemove.push(entity);
×
UNCOV
90
      return;
×
91
    }
92

UNCOV
93
    delete this._entityIndex[id];
×
UNCOV
94
    if (entity) {
×
UNCOV
95
      entity.scene = null;
×
UNCOV
96
      removeItemFromArray(entity, this.entities);
×
UNCOV
97
      this._world.queryManager.removeEntity(entity);
×
98

99
      // if entity has children
UNCOV
100
      entity.children.forEach((c) => {
×
UNCOV
101
        c.scene = null;
×
UNCOV
102
        this.removeEntity(c, deferred);
×
103
      });
UNCOV
104
      const childAddedHandler = this._childAddedHandlerMap.get(entity);
×
UNCOV
105
      if (childAddedHandler) {
×
UNCOV
106
        entity.childrenAdded$.unsubscribe(childAddedHandler);
×
107
      }
UNCOV
108
      const childRemovedHandler = this._childRemovedHandlerMap.get(entity);
×
UNCOV
109
      if (childRemovedHandler) {
×
UNCOV
110
        entity.childrenRemoved$.unsubscribe(childRemovedHandler);
×
111
      }
112

113
      // stats
UNCOV
114
      if (this._world?.scene?.engine) {
×
UNCOV
115
        this._world.scene.engine.stats.currFrame.actors.killed++;
×
116
      }
117
    }
118
  }
119

UNCOV
120
  private _entitiesToRemove: Entity[] = [];
×
121
  public processEntityRemovals(): void {
UNCOV
122
    for (let entityIndex = 0; entityIndex < this._entitiesToRemove.length; entityIndex++) {
×
UNCOV
123
      const entity = this._entitiesToRemove[entityIndex];
×
UNCOV
124
      if (entity.isActive) {
×
125
        continue;
×
126
      }
UNCOV
127
      this.removeEntity(entity, false);
×
128
    }
UNCOV
129
    this._entitiesToRemove.length = 0;
×
130
  }
131

132
  public processComponentRemovals(): void {
UNCOV
133
    for (let entityIndex = 0; entityIndex < this.entities.length; entityIndex++) {
×
UNCOV
134
      const entity = this.entities[entityIndex];
×
UNCOV
135
      entity.processComponentRemoval();
×
136
    }
137
  }
138

139
  public getById(id: number): Entity | undefined {
UNCOV
140
    return this._entityIndex[id];
×
141
  }
142

143
  public getByName(name: string): Entity[] {
UNCOV
144
    return this.entities.filter((e) => e.name === name);
×
145
  }
146

147
  public clear(): void {
UNCOV
148
    for (let i = this.entities.length - 1; i >= 0; i--) {
×
UNCOV
149
      this.removeEntity(this.entities[i]);
×
150
    }
151
  }
152
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc