Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Debug Draw Static Helpers #2929

Merged
merged 13 commits into from
Feb 15, 2024
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Added

- Added new `ex.Debug` static for more convenient debug drawing where you might not have a graphics context accessible to you. This works by batching up all the debug draw requests and flushing them during the debug draw step.
* `ex.Debug.drawRay(ray: Ray, options?: { distance?: number, color?: Color })`
* `ex.Debug.drawBounds(boundingBox: BoundingBox, options?: { color?: Color })`
* `ex.Debug.drawCircle(center: Vector, radius: number, options?: ...)`
* `ex.Debug.drawPolygon(points: Vector[], options?: { color?: Color })`
* `ex.Debug.drawText(text: string, pos: Vector)`
* `ex.Debug.drawLine(start: Vector, end: Vector, options?: LineGraphicsOptions)`
* `ex.Debug.drawLines(points: Vector[], options?: LineGraphicsOptions)`
* `drawPoint(point: Vector, options?: PointGraphicsOptions)`
- Experimental `ex.coroutine` for running code that changes over time, useful for modeling complex animation code. Coroutines return a promise when they are complete. You can think of each `yield` as a frame.
* The result of a yield is the current elapsed time
* You can yield a number in milliseconds and it will wait that long before resuming
Expand Down
33 changes: 29 additions & 4 deletions sandbox/src/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,17 @@ var game = new ex.Engine({
pointerScope: ex.PointerScope.Canvas,
displayMode: ex.DisplayMode.FitScreenAndZoom,
snapToPixel: false,
// fixedUpdateFps: 30,
pixelRatio: 2,
fixedUpdateFps: 60,
maxFps: 60,
antialiasing: false,
antialiasing: {
pixelArtSampler: true,
canvasImageRendering: 'auto',
nativeContextAntialiasing: false,
filtering: ex.ImageFiltering.Pixel,
multiSampleAntialiasing: true,
},
uvPadding: 0,
physics: {
colliders: {
Expand Down Expand Up @@ -555,9 +563,9 @@ player.onPostUpdate = (engine) => {
});
// console.log(hits);
}
player.graphics.onPostDraw = (ctx) => {
ctx.drawLine(ex.Vector.Zero, ex.Vector.Down.scale(100), ex.Color.Red, 2);
}
// player.graphics.onPostDraw = (ctx) => {
// ctx.drawLine(ex.Vector.Zero, ex.Vector.Down.scale(100), ex.Color.Red, 2);
// }
player.body.canSleep = false;
player.graphics.copyGraphics = false;
follower.actions
Expand Down Expand Up @@ -594,6 +602,23 @@ var healthbar = new ex.Actor({
height: 5,
color: new ex.Color(0, 255, 0)});
player.addChild(healthbar);
player.onPostUpdate = () => {
ex.Debug.drawLine(
player.pos,
player.pos.add(ex.Vector.Down.scale(100)), {
color: ex.Color.Red
});
ex.Debug.drawPoint(player.pos, {
size: 1,
color: ex.Color.Violet
});
ex.Debug.drawCircle(player.pos, 100, {
color: ex.Color.Transparent,
strokeColor: ex.Color.Black,
width: 1
});
ex.Debug.drawBounds(player.collider.bounds, { color: ex.Color.Yellow });
}
// player.onPostDraw = (ctx: CanvasRenderingContext2D) => {
// ctx.fillStyle = 'red';
// ctx.fillRect(0, 0, 100, 100);
Expand Down
2 changes: 1 addition & 1 deletion sandbox/tests/polygon/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,5 @@ var triangulated = shape.triangulate();
actor.collider.set(triangulated);
game.add(actor);


game.currentScene.camera.zoom = .75;
game.start();
33 changes: 27 additions & 6 deletions src/engine/Collision/BoundingBox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,34 @@ export class BoundingBox {
return 2 * (wx + wy);
}


// Cache bounding box point returns
private _points: Vector[] = [];
private _left?: number;
private _right?: number;
private _top?: number;
private _bottom?: number;

/**
* Returns the world space points that make up the corners of the bounding box as a polygon
*/
public getPoints(): Vector[] {
const results = [];
results.push(new Vector(this.left, this.top));
results.push(new Vector(this.right, this.top));
results.push(new Vector(this.right, this.bottom));
results.push(new Vector(this.left, this.bottom));
return results;
if (this._left !== this.left ||
this._right !== this.right ||
this._top !== this.top ||
this._bottom !== this.bottom
) {
this._points.length = 0;
this._points.push(new Vector(this.left, this.top));
this._points.push(new Vector(this.right, this.top));
this._points.push(new Vector(this.right, this.bottom));
this._points.push(new Vector(this.left, this.bottom));
this._left = this.left;
this._right = this.right;
this._top = this.top;
this._bottom = this.bottom;
}
return this._points;
}

/**
Expand Down
13 changes: 4 additions & 9 deletions src/engine/Collision/Colliders/PolygonCollider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { AffineMatrix } from '../../Math/affine-matrix';
import { Ray } from '../../Math/ray';
import { ClosestLineJumpTable } from './ClosestLineJumpTable';
import { Collider } from './Collider';
import { BodyComponent, ExcaliburGraphicsContext, Logger } from '../..';
import { BodyComponent, Debug, ExcaliburGraphicsContext, Logger } from '../..';
import { CompositeCollider } from './CompositeCollider';
import { Shape } from './Shape';
import { Transform } from '../../Math/transform';
Expand Down Expand Up @@ -46,6 +46,7 @@ export class PolygonCollider extends Collider {
public flagDirty() {
this._localBoundsDirty = true;
this._localSidesDirty = true;
this._transformedPointsDirty = true;
this._sidesDirty = true;
}

Expand Down Expand Up @@ -701,13 +702,7 @@ export class PolygonCollider extends Collider {
}

public debug(ex: ExcaliburGraphicsContext, color: Color, options?: { lineWidth: number, pointSize: number }) {
const firstPoint = this.getTransformedPoints()[0];
const points = [firstPoint, ...this.getTransformedPoints(), firstPoint];
const { lineWidth, pointSize } = { ...{ lineWidth: 1, pointSize: 1 }, ...options };
for (let i = 0; i < points.length - 1; i++) {
ex.drawLine(points[i], points[i + 1], color, lineWidth);
ex.drawCircle(points[i], pointSize, color);
ex.drawCircle(points[i + 1], pointSize, color);
}
const points = this.getTransformedPoints();
Debug.drawPolygon(points, { color });
}
}
5 changes: 3 additions & 2 deletions src/engine/Debug/Debug.ts → src/engine/Debug/DebugConfig.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DebugFlags, ColorBlindFlags } from './DebugFlags';
import { ColorBlindFlags } from './DebugFlags';
import { Engine } from '../Engine';
import { Color } from '../Color';
import { CollisionContact } from '../Collision/Detection/CollisionContact';
Expand Down Expand Up @@ -152,7 +152,7 @@ export interface GraphicsStatistics {
* best to do so on the `postupdate` event for [[Engine]], after all values have been
* updated during a frame.
*/
export class Debug implements DebugFlags {
export class DebugConfig {
private _engine: Engine;

constructor(engine: Engine) {
Expand Down Expand Up @@ -309,6 +309,7 @@ export class Debug implements DebugFlags {
collisionNormalColor: Color.Cyan,

showCollisionContacts: true,
contactSize: 2,
collisionContactColor: Color.Red
};

Expand Down
4 changes: 0 additions & 4 deletions src/engine/Debug/DebugFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ import { ColorBlindnessPostProcessor } from '../Graphics/PostProcessor/ColorBlin
import { Engine } from '../Engine';
import { ExcaliburGraphicsContextWebGL } from '../Graphics/Context/ExcaliburGraphicsContextWebGL';

export interface DebugFlags {
colorBlindMode: ColorBlindFlags;
}

export class ColorBlindFlags {
private _engine: Engine;
private _colorBlindPostProcessor: ColorBlindnessPostProcessor;
Expand Down
15 changes: 14 additions & 1 deletion src/engine/Debug/DebugSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { GraphicsComponent } from '../Graphics/GraphicsComponent';
import { Particle } from '../Particles';
import { DebugGraphicsComponent } from '../Graphics/DebugGraphicsComponent';
import { CoordPlane } from '../Math/coord-plane';
import { Debug } from '../Graphics/Debug';

export class DebugSystem extends System {
public readonly systemType = SystemType.Draw;
Expand Down Expand Up @@ -260,7 +261,10 @@ export class DebugSystem extends System {
for (const [_, contact] of this._engine.debug.stats.currFrame.physics.contacts) {
if (physicsSettings.showAll || physicsSettings.showCollisionContacts) {
for (const point of contact.points) {
this._graphicsContext.debug.drawPoint(point, { size: 5, color: physicsSettings.collisionContactColor });
this._graphicsContext.debug.drawPoint(point, {
size: physicsSettings.contactSize,
color: physicsSettings.collisionContactColor
});
}
}

Expand Down Expand Up @@ -290,6 +294,15 @@ export class DebugSystem extends System {
this._graphicsContext.flush();
}

postupdate(engine: Scene<unknown>, elapsedMs: number): void {
this._graphicsContext.save();
if (this._camera) {
this._camera.draw(this._graphicsContext);
}
Debug.flush(this._graphicsContext);
this._graphicsContext.restore();
}

/**
* This applies the current entity transform to the graphics context
* @param entity
Expand Down
2 changes: 1 addition & 1 deletion src/engine/Debug/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './Debug';
export * from './DebugConfig';
export * from './DebugFlags';
export * from './DebugSystem';
6 changes: 3 additions & 3 deletions src/engine/Engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { Logger, LogLevel } from './Util/Log';
import { Color } from './Color';
import { Scene, SceneConstructor, isSceneConstructor } from './Scene';
import { Entity } from './EntityComponentSystem/Entity';
import { Debug, DebugStats } from './Debug/Debug';
import { DebugConfig, DebugStats } from './Debug/DebugConfig';
import { BrowserEvents } from './Util/Browser';
import {
AntialiasOptions,
Expand Down Expand Up @@ -505,7 +505,7 @@ export class Engine<TKnownScenes extends string = any> implements CanInitialize,
* * Graphics
* * Colliders
*/
public debug: Debug;
public debug: DebugConfig;

/**
* Access [[stats]] that holds frame statistics.
Expand Down Expand Up @@ -932,7 +932,7 @@ O|===|* >________________>\n\
};
}

this.debug = new Debug(this);
this.debug = new DebugConfig(this);

this.director = new Director(this, options.scenes);

Expand Down
4 changes: 2 additions & 2 deletions src/engine/Graphics/Context/ExcaliburGraphicsContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,11 @@ export interface ExcaliburGraphicsContextState {
material: Material;
}
export interface LineGraphicsOptions {
color: Color;
color?: Color;
}

export interface RectGraphicsOptions {
color: Color;
color?: Color;
}

export interface PointGraphicsOptions {
Expand Down
5 changes: 5 additions & 0 deletions src/engine/Graphics/Context/line-renderer/line-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import { RendererPlugin } from '../renderer';
import { Shader, VertexBuffer, VertexLayout } from '../..';
import { GraphicsDiagnostics } from '../../GraphicsDiagnostics';

export interface LineOptions {
color?: Color;
width?: number;
}

export class LineRenderer implements RendererPlugin {
public readonly type = 'ex.line';
public priority: number = 0;
Expand Down
107 changes: 107 additions & 0 deletions src/engine/Graphics/Debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { Vector } from '../Math/vector';
import { ExcaliburGraphicsContext, LineGraphicsOptions, PointGraphicsOptions } from './Context/ExcaliburGraphicsContext';
import { Color } from '../Color';
import { Ray } from '../Math/ray';
import { BoundingBox } from '../excalibur';

export class Debug {
static _drawCalls: ((ctx: ExcaliburGraphicsContext) => void)[] = [];
static _ctx: ExcaliburGraphicsContext;
static z: number = Infinity;
static registerGraphicsContext(ctx: ExcaliburGraphicsContext) {
Debug._ctx = ctx;
}
static draw(debugDrawCall: (ctx: ExcaliburGraphicsContext) => void) {
this._drawCalls.push(debugDrawCall);
}

static drawPoint(point: Vector, options?: PointGraphicsOptions) {
Debug.draw(ctx => {
ctx.debug.drawPoint(point, options);
});
}

static drawLine(start: Vector, end: Vector, options?: LineGraphicsOptions) {
Debug.draw(ctx => {
ctx.debug.drawLine(start, end, options);
});
}

static drawLines(points: Vector[], options?: LineGraphicsOptions) {
if (points.length > 1) {
Debug.draw(ctx => {
for (let i = 0; i < points.length - 1; i++) {
ctx.debug.drawLine(points[i], points[i + 1], options);
}
});
}
}

static drawText(text: string, pos: Vector) {
Debug.draw(ctx => {
ctx.debug.drawText(text, pos);
});
}

static drawPolygon(points: Vector[], options?: { color?: Color }) {
if (points.length > 1) {
Debug.draw(ctx => {
const firstPoint = points[0];
const polygon = [...points, firstPoint];
for (let i = 0; i < polygon.length - 1; i++) {
ctx.debug.drawLine(polygon[i], polygon[i + 1], options);
}
});
}
}

static drawCircle(center: Vector, radius: number, options?: {
color?: Color,
strokeColor?: Color,
width?: number
}) {
const { color, strokeColor, width} = {
color: Color.Black,
strokeColor: undefined,
width: undefined,
...options
};
Debug.draw(ctx => {
ctx.drawCircle(center, radius, color, strokeColor, width);
});
}

static drawBounds(boundingBox: BoundingBox, options?: { color?: Color }): void {
Debug.draw(ctx => {
ctx.debug.drawRect(boundingBox.left, boundingBox.top, boundingBox.width, boundingBox.height, options);
});
}

static drawRay(ray: Ray, options?: { distance?: number, color?: Color }) {
const { distance, color } = {
color: Color.Blue,
distance: 10,
...options
};
Debug.draw((ctx) => {
const start = ray.pos;
const end = ray.pos.add(ray.dir.scale(distance));

ctx.debug.drawLine(start, end, { color });
});
}

static flush(ctx: ExcaliburGraphicsContext) {
ctx.save();
ctx.z = Debug.z;
for (const drawCall of Debug._drawCalls) {
drawCall(ctx);
}
ctx.restore();
Debug.clear();
}

static clear() {
Debug._drawCalls.length = 0;
}
}
Loading