From 951e839a0d3fdc817fada31c61ddf2cdff7912e9 Mon Sep 17 00:00:00 2001 From: Erik Onarheim Date: Fri, 29 Sep 2023 18:33:32 -0500 Subject: [PATCH] fix: [#2773] Line bounds are now correct (#2774) Closes #2773 ## Changes: - Update bounds calculation on Lines to be correct from the geometry - Fix tests --- CHANGELOG.md | 1 + sandbox/tests/linebounds/index.html | 13 +++++ sandbox/tests/linebounds/index.ts | 82 +++++++++++++++++++++++++++++ src/engine/Graphics/Line.ts | 24 ++++++++- src/spec/LineSpec.ts | 27 ++++++++-- 5 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 sandbox/tests/linebounds/index.html create mode 100644 sandbox/tests/linebounds/index.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cbf7da3..52c5186e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Fixed issue with input mapper where `keyboard.wasPressed(...)` did not fire +- Fixed issue where the ex.Line graphics bounds were incorrect causing erroneous offscreen culling ### Updates diff --git a/sandbox/tests/linebounds/index.html b/sandbox/tests/linebounds/index.html new file mode 100644 index 00000000..97ac7263 --- /dev/null +++ b/sandbox/tests/linebounds/index.html @@ -0,0 +1,13 @@ + + + + + + Line Bounds + + + + + + + \ No newline at end of file diff --git a/sandbox/tests/linebounds/index.ts b/sandbox/tests/linebounds/index.ts new file mode 100644 index 00000000..ee03909b --- /dev/null +++ b/sandbox/tests/linebounds/index.ts @@ -0,0 +1,82 @@ +var game = new ex.Engine({ + width: 1200, + height: 400, + canvasElementId: "game", + pixelRatio: 1 +}); + +game.debug.entity.showName = true; +game.toggleDebug() + +var actor = new ex.Actor({ + pos: new ex.Vector(100, 100), + width: 50, + height: 50, + color: ex.Color.Red +}); + +class Beam extends ex.Actor { + public length; + + constructor(options, length) { + super(options); + this.graphics.anchor = ex.Vector.Zero; + this.length = length; + const longLine = new ex.Line({ + start: ex.vec(0, 0), + end: ex.vec(this.length, 0), + thickness: 26, + color: ex.Color.White + }); + // longLine.height = 26; + console.log(longLine.width, longLine.height); + console.log(this.graphics.localBounds); + + this.graphics.use(longLine); + } + + onPreUpdate() { + + } +} + +var shortBeam = new Beam( + { + name: "shortBeam", + pos: new ex.Vector(200, 200) + }, + 100 +); + +var longBeam = new Beam( + { + name: "longBeam", + pos: new ex.Vector(200, 300) + }, + 1001 +); + +longBeam.vel.x = -100; + +var shortLine = new ex.Line({ + start: ex.vec(0, 0), + end: ex.vec(10, 30), + thickness: 26, + color: ex.Color.Green +}); + +var longLine = new ex.Line({ + start: ex.vec(0, 0), + end: ex.vec(4000, 0), + thickness: 26, + color: ex.Color.Yellow +}); + +actor.graphics.anchor = ex.Vector.Zero; +actor.graphics.add(shortLine); +actor.graphics.add(longLine); + +game.add(actor); +game.add(shortBeam); +game.add(longBeam); +game.start(); diff --git a/src/engine/Graphics/Line.ts b/src/engine/Graphics/Line.ts index 701d87c5..3317f113 100644 --- a/src/engine/Graphics/Line.ts +++ b/src/engine/Graphics/Line.ts @@ -15,6 +15,7 @@ export class Line extends Graphic { readonly end: Vector; color: Color = Color.Black; thickness: number = 1; + private _localBounds: BoundingBox; constructor(options: LineOptions) { super(); const { start, end, color, thickness } = options; @@ -22,11 +23,32 @@ export class Line extends Graphic { this.end = end; this.color = color ?? this.color; this.thickness = thickness ?? this.thickness; - const { width, height } = BoundingBox.fromPoints([start, end]); + this._localBounds = this._calculateBounds(); + const { width, height } = this._localBounds; + this.width = width; this.height = height; } + public get localBounds() { + return this._localBounds; + } + + private _calculateBounds(): BoundingBox { + const lineNormal = this.end.sub(this.start).normal(); + + const halfThickness = this.thickness / 2; + + const points = [ + this.start.add(lineNormal.scale(halfThickness)), + this.end.add(lineNormal.scale(halfThickness)), + this.end.add(lineNormal.scale(-halfThickness)), + this.start.add(lineNormal.scale(-halfThickness)) + ]; + + return BoundingBox.fromPoints(points); + } + protected _drawImage(ctx: ExcaliburGraphicsContext, _x: number, _y: number): void { ctx.drawLine(this.start, this.end, this.color, this.thickness); } diff --git a/src/spec/LineSpec.ts b/src/spec/LineSpec.ts index ab5cc19b..c13dee25 100644 --- a/src/spec/LineSpec.ts +++ b/src/spec/LineSpec.ts @@ -41,13 +41,34 @@ describe('A Line', () => { it('has correct local bounds', () => { const sut = new ex.Line({ start: ex.vec(0, 0), - end: ex.vec(50, 70), + end: ex.vec(50, 50), color: ex.Color.Green, thickness: 5 }); - expect(sut.width).toBe(50); - expect(sut.height).toBe(70); + expect(sut.localBounds.left).toBeCloseTo(-1.767, 2); + expect(sut.localBounds.top).toBeCloseTo(-1.767, 2); + expect(sut.localBounds.bottom).toBeCloseTo(51.767, 2); + expect(sut.localBounds.right).toBeCloseTo(51.767, 2); + + expect(sut.width).toBeCloseTo(53.535, 2); + expect(sut.height).toBeCloseTo(53.535, 2); + }); + + it('has correct bounds when horizontal', () => { + const sut = new ex.Line({ + start: ex.vec(0, 0), + end: ex.vec(1000, 0), + thickness: 4 + }); + + expect(sut.localBounds.left).toBe(0); + expect(sut.localBounds.top).toBe(-2); + expect(sut.localBounds.bottom).toBe(2); + expect(sut.localBounds.right).toBe(1000); + + expect(sut.width).toBe(1000); + expect(sut.height).toBe(4); }); it('can draw a line', async () => { -- 2.51.2