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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672import { ColorBlindFlags } from './debug-flags';import type { Engine } from '../engine';import { Color } from '../color';import type { CollisionContact } from '../collision/detection/collision-contact';import type { StandardClock, TestClock } from '../util/clock';import { Debug } from '../graphics/debug';
/** * Debug stats containing current and previous frame statistics */export interface DebugStats { currFrame: FrameStats; prevFrame: FrameStats;}
/** * Represents a frame's individual statistics */export interface FrameStatistics { /** * The number of the frame */ id: number;
/** * Gets the frame's delta (time since last frame scaled by {@apilink Engine.timescale}) (in ms) * * Excalibur extension depends on this */ elapsedMs: number;
/** * Gets the frame's frames-per-second (FPS) */ fps: number;
/** * Duration statistics (in ms) */ duration: FrameDurationStats;
/** * Duration statistics (in ms) for ECS systems */ systemDuration: Record<string, number>;
/** * Actor statistics */ actors: FrameActorStats;
/** * Physics statistics */ physics: PhysicsStatistics;
/** * Graphics statistics */ graphics: GraphicsStatistics;}
/** * Represents actor stats for a frame */export interface FrameActorStats { /** * Gets the frame's number of actors (alive) */ alive: number;
/** * Gets the frame's number of actors (killed) */ killed: number;
/** * Gets the frame's number of remaining actors (alive - killed) */ remaining: number;
/** * Gets the frame's number of UI actors */ ui: number;
/** * Gets the frame's number of total actors (remaining + UI) */ total: number;}
/** * Represents duration stats for a frame */export interface FrameDurationStats { /** * Gets the frame's total time to run the update function (in ms) */ update: number;
/** * Gets the frame's total time to run the draw function (in ms) */ draw: number;
/** * Gets the frame's total render duration (update + draw duration) (in ms) */ total: number;}
/** * Represents physics stats for the current frame */export interface PhysicsStatistics { /** * Gets the number of broadphase collision pairs which */ pairs: number;
/** * Gets the number of actual collisions */ collisions: number;
/** * Copy of the current frame contacts (only updated if debug is toggled on) */ contacts: Map<string, CollisionContact>;
/** * Gets the number of fast moving bodies using raycast continuous collisions in the scene */ fastBodies: number;
/** * Gets the number of bodies that had a fast body collision resolution */ fastBodyCollisions: number;
/** * Gets the time it took to calculate the broadphase pairs */ broadphase: number;
/** * Gets the time it took to calculate the narrowphase */ narrowphase: number;}
export interface GraphicsStatistics { drawCalls: number; drawnImages: number; rendererSwaps: number;}
/** * Debug statistics and flags for Excalibur. If polling these values, it would be * best to do so on the `postupdate` event for {@apilink Engine}, after all values have been * updated during a frame. */export class DebugConfig { private _engine: Engine;
constructor(engine: Engine) { this._engine = engine;
this.colorBlindMode = new ColorBlindFlags(this._engine);
Debug.registerDebugConfig(this); }
/** * Switch the current excalibur clock with the {@apilink TestClock} and return * it in the same running state. * * This is useful when you need to debug frame by frame. */ public useTestClock(): TestClock { const clock = this._engine.clock; const wasRunning = clock.isRunning(); clock.stop();
const testClock = clock.toTestClock(); if (wasRunning) { testClock.start(); } this._engine.clock = testClock; return testClock; }
/** * Switch the current excalibur clock with the {@apilink StandardClock} and * return it in the same running state. * * This is useful when you need to switch back to normal mode after * debugging. */ public useStandardClock(): StandardClock { const currentClock = this._engine.clock; const wasRunning = currentClock.isRunning(); currentClock.stop();
const standardClock = currentClock.toStandardClock(); if (wasRunning) { standardClock.start(); } this._engine.clock = standardClock; return standardClock; }
/** * Performance statistics */ public stats: DebugStats = { /** * Current frame statistics. Engine reuses this instance, use {@apilink FrameStats.clone} to copy frame stats. * Best accessed on {@apilink postframe} event. See {@apilink FrameStats} */ currFrame: new FrameStats(),
/** * Previous frame statistics. Engine reuses this instance, use {@apilink FrameStats.clone} to copy frame stats. * Best accessed on {@apilink preframe} event. Best inspected on engine event `preframe`. See {@apilink FrameStats} */ prevFrame: new FrameStats() };
public settings = { text: { foreground: Color.Black, background: Color.Transparent, border: Color.Transparent }, z: { text: Number.POSITIVE_INFINITY, point: Number.MAX_SAFE_INTEGER - 1, ray: Number.MAX_SAFE_INTEGER - 1, dashed: Number.MAX_SAFE_INTEGER - 2, solid: Number.MAX_SAFE_INTEGER - 3 } };
/** * Correct or simulate color blindness using {@apilink ColorBlindnessPostProcessor}. * @warning Will reduce FPS. */ public colorBlindMode: ColorBlindFlags;
/** * Filter debug context to named entities or entity ids */ public filter: { useFilter: boolean; nameQuery: string; ids: number[] } = { /** * Toggle filter on or off (default off) must be on for DebugDraw to use filters */ useFilter: false, /** * Query for entities by name, if the entity name contains `nameQuery` it will be included */ nameQuery: '', /** * Query for Entity ids, if the id matches it will be included */ ids: [] };
/** * Entity debug settings */ public entity = { showAll: false, showId: false, showName: false };
/** * Transform component debug settings */ public transform = { showAll: false,
showPosition: false, showPositionLabel: false, positionColor: Color.Yellow,
showZIndex: false,
showScale: false, scaleColor: Color.Green,
showRotation: false, rotationColor: Color.Blue };
/** * Graphics component debug settings */ public graphics = { showAll: false,
showBounds: false, boundsColor: Color.Yellow };
/** * Collider component debug settings */ public collider = { showAll: false,
showBounds: false, boundsColor: Color.Blue,
showOwner: false,
showGeometry: true, geometryColor: Color.Green, geometryLineWidth: 2, geometryPointSize: 2 };
/** * Physics simulation debug settings */ public physics = { showAll: false,
showBroadphaseSpacePartitionDebug: false,
showCollisionNormals: false, collisionNormalColor: Color.Cyan,
showCollisionContacts: true, contactSize: 10, collisionContactColor: Color.Red };
/** * Motion component debug settings */ public motion = { showAll: false,
showVelocity: false, velocityColor: Color.Yellow,
showAcceleration: false, accelerationColor: Color.Red };
/** * Body component debug settings */ public body = { showAll: false,
showCollisionGroup: false, showCollisionType: false, showSleeping: false, showMotion: false, showMass: false };
/** * Camera debug settings */ public camera = { showAll: false,
showFocus: false, focusColor: Color.Red,
showZoom: false };
public tilemap = { showAll: false,
showGrid: false, gridColor: Color.Red, gridWidth: 0.5, showSolidBounds: false, solidBoundsColor: Color.fromHex('#8080807F'), // grayish showColliderGeometry: true };
public isometric = { showAll: false, showPosition: false, positionColor: Color.Yellow, positionSize: 1, showGrid: false, gridColor: Color.Red, gridWidth: 1, showColliderGeometry: true };
/** * Screen debug settings * * Visualizes the screen-space coordinate plan, including the safe {@apilink Screen.contentArea} * and the full {@apilink Screen.unsafeArea} (which may be partially offscreen under the * *AndFill display modes). */ public screen = { showAll: false,
showContentArea: true, contentAreaColor: Color.Green,
showUnsafeArea: true, unsafeAreaColor: Color.Red,
showLegend: true, legendColor: Color.White };}
/** * Implementation of a frame's stats. Meant to have values copied via {@apilink FrameStats.reset}, avoid * creating instances of this every frame. */export class FrameStats implements FrameStatistics { private _id: number = 0; private _elapsedMs: number = 0; private _fps: number = 0; private _actorStats: FrameActorStats = { alive: 0, killed: 0, ui: 0, get remaining() { return this.alive - this.killed; }, get total() { return this.remaining + this.ui; } }; private _durationStats: FrameDurationStats = { update: 0, draw: 0, get total() { return this.update + this.draw; } };
private _physicsStats: PhysicsStats = new PhysicsStats();
private _graphicsStats: GraphicsStatistics = { drawCalls: 0, drawnImages: 0, rendererSwaps: 0 };
systemDuration: Record<string, number> = {};
/** * Zero out values or clone other IFrameStat stats. Allows instance reuse. * @param [otherStats] Optional stats to clone */ public reset(otherStats?: FrameStatistics) { if (otherStats) { this.id = otherStats.id; this.elapsedMs = otherStats.elapsedMs; this.fps = otherStats.fps; this.actors.alive = otherStats.actors.alive; this.actors.killed = otherStats.actors.killed; this.actors.ui = otherStats.actors.ui; this.duration.update = otherStats.duration.update; this.duration.draw = otherStats.duration.draw; for (const key in otherStats.systemDuration) { this.systemDuration[key] = otherStats.systemDuration[key]; } this._physicsStats.reset(otherStats.physics); this.graphics.drawCalls = otherStats.graphics.drawCalls; this.graphics.drawnImages = otherStats.graphics.drawnImages; this.graphics.rendererSwaps = otherStats.graphics.rendererSwaps; } else { this.id = this.elapsedMs = this.fps = 0; this.actors.alive = this.actors.killed = this.actors.ui = 0; this.duration.update = this.duration.draw = 0; this._physicsStats.reset(); this.graphics.drawnImages = this.graphics.drawCalls = this.graphics.rendererSwaps = 0; for (const key in this.systemDuration) { this.systemDuration[key] = 0; } } }
/** * Provides a clone of this instance. */ public clone(): FrameStats { const fs = new FrameStats();
fs.reset(this);
return fs; }
/** * Gets the frame's id */ public get id() { return this._id; }
/** * Sets the frame's id */ public set id(value: number) { this._id = value; }
/** * Gets the frame's delta (time since last frame) */ public get elapsedMs() { return this._elapsedMs; }
/** * Sets the frame's delta (time since last frame). Internal use only. * @internal */ public set elapsedMs(value: number) { this._elapsedMs = value; }
/** * Gets the frame's frames-per-second (FPS) */ public get fps() { return this._fps; }
/** * Sets the frame's frames-per-second (FPS). Internal use only. * @internal */ public set fps(value: number) { this._fps = value; }
/** * Gets the frame's actor statistics */ public get actors() { return this._actorStats; }
/** * Gets the frame's duration statistics */ public get duration() { return this._durationStats; }
/** * Gets the frame's physics statistics */ public get physics() { return this._physicsStats; }
/** * Gets the frame's graphics statistics */ public get graphics() { return this._graphicsStats; }}
export class PhysicsStats implements PhysicsStatistics { private _pairs: number = 0; private _collisions: number = 0; private _contacts: Map<string, CollisionContact> = new Map(); private _fastBodies: number = 0; private _fastBodyCollisions: number = 0; private _broadphase: number = 0; private _narrowphase: number = 0;
/** * Zero out values or clone other IPhysicsStats stats. Allows instance reuse. * @param [otherStats] Optional stats to clone */ public reset(otherStats?: PhysicsStatistics) { if (otherStats) { this.pairs = otherStats.pairs; this.collisions = otherStats.collisions; this.contacts = otherStats.contacts; this.fastBodies = otherStats.fastBodies; this.fastBodyCollisions = otherStats.fastBodyCollisions; this.broadphase = otherStats.broadphase; this.narrowphase = otherStats.narrowphase; } else { this.pairs = this.collisions = this.fastBodies = 0; this.fastBodyCollisions = this.broadphase = this.narrowphase = 0; this.contacts.clear(); } }
/** * Provides a clone of this instance. */ public clone(): PhysicsStatistics { const ps = new PhysicsStats();
ps.reset(this);
return ps; }
public get pairs(): number { return this._pairs; }
public set pairs(value: number) { this._pairs = value; }
public get collisions(): number { return this._collisions; }
public set collisions(value: number) { this._collisions = value; }
public get contacts(): Map<string, CollisionContact> { return this._contacts; }
public set contacts(contacts: Map<string, CollisionContact>) { this._contacts = contacts; }
public get fastBodies(): number { return this._fastBodies; }
public set fastBodies(value: number) { this._fastBodies = value; }
public get fastBodyCollisions(): number { return this._fastBodyCollisions; }
public set fastBodyCollisions(value: number) { this._fastBodyCollisions = value; }
public get broadphase(): number { return this._broadphase; }
public set broadphase(value: number) { this._broadphase = value; }
public get narrowphase(): number { return this._narrowphase; }
public set narrowphase(value: number) { this._narrowphase = value; }}