Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/excaliburjs/Excalibur. 🎮 Your friendly TypeScript 2D game engine for the web 🗡️ excaliburjs.com
excalibur excaliburjs game-development game-engine game-framework gamedev games html5-canvas typescript
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687import { GraphicsComponent } from './graphics-component';import { EnterViewportEvent, ExitViewportEvent } from '../events';import type { Scene } from '../scene';import type { Screen } from '../screen';import { TransformComponent } from '../entity-component-system/components/transform-component';import type { Camera } from '../camera';import { System, SystemType } from '../entity-component-system//system';import { ParallaxComponent } from './parallax-component';import { Vector } from '../math/vector';import { CoordPlane } from '../math/coord-plane';import type { BoundingBox } from '../collision/bounding-box';import type { Query, World } from '../entity-component-system';import { SystemPriority } from '../entity-component-system';
export class OffscreenSystem extends System { static override priority: number = SystemPriority.Higher;
public systemType = SystemType.Draw; private _camera!: Camera; private _screen!: Screen; private _worldBounds!: BoundingBox; query: Query<typeof TransformComponent | typeof GraphicsComponent>;
constructor(public world: World) { super(); this.query = this.world.query([TransformComponent, GraphicsComponent]); }
public override initialize(world: World, scene: Scene): void { this._camera = scene.camera; this._screen = scene.engine.screen; }
update(): void { this._worldBounds = this._screen.getWorldBounds(); let transform: TransformComponent; let graphics: GraphicsComponent; let maybeParallax: ParallaxComponent | undefined;
for (let i = 0; i < this.query.entities.length; i++) { const entity = this.query.entities[i]; graphics = entity.get(GraphicsComponent); transform = entity.get(TransformComponent); maybeParallax = entity.get(ParallaxComponent);
let parallaxOffset: Vector | undefined; if (maybeParallax) { // We use the Tiled formula // https://doc.mapeditor.org/en/latest/manual/layers/#parallax-scrolling-factor // cameraPos * (1 - parallaxFactor) const oneMinusFactor = Vector.One.sub(maybeParallax.parallaxFactor); parallaxOffset = this._camera.pos.scale(oneMinusFactor); }
// Figure out if entities are offscreen const entityOffscreen = this._isOffscreen(transform, graphics, parallaxOffset); if (entityOffscreen && !entity.hasTag('ex.offscreen')) { entity.events.emit('exitviewport', new ExitViewportEvent(entity)); entity.addTag('ex.offscreen'); }
if (!entityOffscreen && entity.hasTag('ex.offscreen')) { entity.events.emit('enterviewport', new EnterViewportEvent(entity)); entity.removeTag('ex.offscreen'); } } }
private _isOffscreen(transform: TransformComponent, graphics: GraphicsComponent, parallaxOffset: Vector | undefined) { if (graphics.forceOnScreen) { return false; } if (transform.coordPlane === CoordPlane.World) { let bounds = graphics.localBounds; if (parallaxOffset) { bounds = bounds.translate(parallaxOffset); } const transformedBounds = bounds.transform(transform.get().matrix); const graphicsOffscreen = !this._worldBounds.overlaps(transformedBounds); return graphicsOffscreen; } else { // TODO screen coordinates return false; } }}