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

excaliburjs / Excalibur / 29113721976

10 Jul 2026 06:12PM UTC coverage: 88.902% (-0.004%) from 88.906%
29113721976

Pull #3793

github

web-flow
Merge e34b9fb0f into 3ee8a530a
Pull Request #3793: chore: TS6 Upgrades + Typedoc update

6933 of 9094 branches covered (76.24%)

279 of 378 new or added lines in 58 files covered. (73.81%)

3 existing lines in 2 files now uncovered.

15517 of 17454 relevant lines covered (88.9%)

24916.19 hits per line

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

60.87
/src/engine/trigger.ts
1
import type { Vector } from './math/vector';
2
import type { CollisionEndEvent, CollisionStartEvent } from './events';
3
import { ExitTriggerEvent, EnterTriggerEvent } from './events';
4
import { CollisionType } from './collision/collision-type';
5
import type { Entity } from './entity-component-system';
6
import type { ActorArgs, ActorEvents } from './actor';
7
import { Actor } from './actor';
8
import { EventEmitter } from './event-emitter';
9

10
export interface TriggerEvents extends ActorEvents {
11
  exit: ExitTriggerEvent;
12
  enter: EnterTriggerEvent;
13
}
14

15
export const TriggerEvents = {
254✔
16
  ExitTrigger: 'exit',
17
  EnterTrigger: 'enter'
18
};
19

20
/**
21
 * TriggerOptions
22
 */
23
export interface TriggerOptions {
24
  // position of the trigger
25
  pos?: Vector;
26
  // width of the trigger
27
  width?: number;
28
  // height of the trigger
29
  height?: number;
30
  // whether the trigger is visible or not
31
  visible?: boolean;
32
  // action to take when triggered
33
  action?: (entity: Entity) => void;
34
  // if specified the trigger will only fire on a specific entity and overrides any filter
35
  target?: Entity;
36
  // Returns true if the triggers should fire on the collided entity
37
  filter?: (entity: Entity) => boolean;
38
  // -1 if it should repeat forever
39
  repeat?: number;
40
}
41

42
/**
43
 * Triggers are a method of firing arbitrary code on collision. These are useful
44
 * as 'buttons', 'switches', or to trigger effects in a game. By default triggers
45
 * are invisible, and can only be seen when {@apilink Trigger.visible} is set to `true`.
46
 */
47
export class Trigger extends Actor {
48
  public events = new EventEmitter<TriggerEvents & ActorEvents>();
4✔
49
  public target?: Entity;
50
  /**
51
   * Action to fire when triggered by collision
52
   */
53
  public action: (entity: Entity) => void;
54
  /**
55
   * Filter to add additional granularity to action dispatch, if a filter is specified the action will only fire when
56
   * filter return true for the collided entity.
57
   */
58
  public filter: (entity: Entity) => boolean;
59
  /**
60
   * Number of times to repeat before killing the trigger,
61
   */
62
  public repeat: number;
63

64
  /**
65
   * @param options Trigger options
66
   */
67
  constructor(options: TriggerOptions & ActorArgs) {
68
    super({ ...options });
4✔
69

70
    this.filter = options.filter ?? (() => true);
4✔
71
    this.repeat = options.repeat ?? -1;
4!
72
    this.action = options.action ?? (() => undefined);
4!
73
    this.target = options.target;
4✔
74

75
    this.graphics.isVisible = options.visible ?? false;
4✔
76
    this.body.collisionType = CollisionType.Passive;
4✔
77

78
    this.events.on('collisionstart', ({ other: collider }: CollisionStartEvent) => {
4✔
79
      if (!this._matchesTarget(collider.owner!)) {
2!
80
        return;
2✔
81
      }
82

NEW
83
      this.events.emit('enter', new EnterTriggerEvent(this, collider.owner!));
×
NEW
84
      this._dispatchAction(collider.owner!);
×
85
      // remove trigger if its done, -1 repeat forever
86
      if (this.repeat === 0) {
×
87
        this.kill();
×
88
      }
89
    });
90

91
    this.events.on('collisionend', ({ other: collider }: CollisionEndEvent) => {
4✔
NEW
92
      if (this._matchesTarget(collider.owner!)) {
×
NEW
93
        this.events.emit('exit', new ExitTriggerEvent(this, collider.owner!));
×
94
      }
95
    });
96
  }
97

98
  private _matchesTarget(entity: Entity): boolean {
99
    return this.filter(entity) && (this.target === undefined || this.target === entity);
2✔
100
  }
101

102
  private _dispatchAction(target: Entity) {
103
    if (this.repeat !== 0) {
×
104
      this.action.call(this, target);
×
105
      this.repeat--;
×
106
    }
107
  }
108
}
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