• 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

3.03
/src/engine/Graphics/OffscreenSystem.ts
1
import { GraphicsComponent } from './GraphicsComponent';
2
import { EnterViewPortEvent, ExitViewPortEvent } from '../Events';
3
import { Scene } from '../Scene';
4
import { Screen } from '../Screen';
5
import { TransformComponent } from '../EntityComponentSystem/Components/TransformComponent';
6
import { Camera } from '../Camera';
7
import { System, SystemType } from '../EntityComponentSystem/System';
8
import { ParallaxComponent } from './ParallaxComponent';
9
import { Vector } from '../Math/vector';
10
import { CoordPlane } from '../Math/coord-plane';
11
import { BoundingBox } from '../Collision/BoundingBox';
12
import { Query, SystemPriority, World } from '../EntityComponentSystem';
13

14
export class OffscreenSystem extends System {
15
  static priority: number = SystemPriority.Higher;
1✔
16

UNCOV
17
  public systemType = SystemType.Draw;
×
18
  private _camera!: Camera;
19
  private _screen!: Screen;
20
  private _worldBounds!: BoundingBox;
21
  query: Query<typeof TransformComponent | typeof GraphicsComponent>;
22

UNCOV
23
  constructor(public world: World) {
×
UNCOV
24
    super();
×
UNCOV
25
    this.query = this.world.query([TransformComponent, GraphicsComponent]);
×
26
  }
27

28
  public initialize(world: World, scene: Scene): void {
UNCOV
29
    this._camera = scene.camera;
×
UNCOV
30
    this._screen = scene.engine.screen;
×
31
  }
32

33
  update(): void {
UNCOV
34
    this._worldBounds = this._screen.getWorldBounds();
×
35
    let transform: TransformComponent;
36
    let graphics: GraphicsComponent;
37
    let maybeParallax: ParallaxComponent | undefined;
38

UNCOV
39
    for (let i = 0; i < this.query.entities.length; i++) {
×
UNCOV
40
      const entity = this.query.entities[i];
×
UNCOV
41
      graphics = entity.get(GraphicsComponent);
×
UNCOV
42
      transform = entity.get(TransformComponent);
×
UNCOV
43
      maybeParallax = entity.get(ParallaxComponent);
×
44

45
      let parallaxOffset: Vector | undefined;
UNCOV
46
      if (maybeParallax) {
×
47
        // We use the Tiled formula
48
        // https://doc.mapeditor.org/en/latest/manual/layers/#parallax-scrolling-factor
49
        // cameraPos * (1 - parallaxFactor)
UNCOV
50
        const oneMinusFactor = Vector.One.sub(maybeParallax.parallaxFactor);
×
UNCOV
51
        parallaxOffset = this._camera.pos.scale(oneMinusFactor);
×
52
      }
53

54
      // Figure out if entities are offscreen
UNCOV
55
      const entityOffscreen = this._isOffscreen(transform, graphics, parallaxOffset);
×
UNCOV
56
      if (entityOffscreen && !entity.hasTag('ex.offscreen')) {
×
UNCOV
57
        entity.events.emit('exitviewport', new ExitViewPortEvent(entity));
×
UNCOV
58
        entity.addTag('ex.offscreen');
×
59
      }
60

UNCOV
61
      if (!entityOffscreen && entity.hasTag('ex.offscreen')) {
×
UNCOV
62
        entity.events.emit('enterviewport', new EnterViewPortEvent(entity));
×
UNCOV
63
        entity.removeTag('ex.offscreen');
×
64
      }
65
    }
66
  }
67

68
  private _isOffscreen(transform: TransformComponent, graphics: GraphicsComponent, parallaxOffset: Vector | undefined) {
UNCOV
69
    if (graphics.forceOnScreen) {
×
UNCOV
70
      return false;
×
71
    }
UNCOV
72
    if (transform.coordPlane === CoordPlane.World) {
×
UNCOV
73
      let bounds = graphics.localBounds;
×
UNCOV
74
      if (parallaxOffset) {
×
UNCOV
75
        bounds = bounds.translate(parallaxOffset);
×
76
      }
UNCOV
77
      const transformedBounds = bounds.transform(transform.get().matrix);
×
UNCOV
78
      const graphicsOffscreen = !this._worldBounds.overlaps(transformedBounds);
×
UNCOV
79
      return graphicsOffscreen;
×
80
    } else {
81
      // TODO screen coordinates
UNCOV
82
      return false;
×
83
    }
84
  }
85
}
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