Skip to content

Commit

Permalink
feat: Fast BoundingBox overlap and transform (#2241)
Browse files Browse the repository at this point in the history
Performance improvements, implements a fast `ex.BoundingBox.overlap(...)` and `ex.BoundingBox.transform(...)`
  • Loading branch information
eonarheim authored Feb 12, 2022
1 parent e11b0ea commit 7bd8a82
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 4 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Added

Added arbitrary non-convex polygon support (only non-self intersecting) with `ex.PolygonCollider(...).triangulate()` which builds a new `ex.CompositeCollider` composed of triangles.
- Added arbitrary non-convex polygon support (only non-self intersecting) with `ex.PolygonCollider(...).triangulate()` which builds a new `ex.CompositeCollider` composed of triangles.
- Added faster `ex.BoundingBox.transform(...)` implementation.
- Added faster `ex.BoundingBox.overlap(...)` implementation.
- Added `ex.Vector.min(...)` and `ex.Vector.max(...)` to find the min/max of each vector component between 2 vectors.

### Fixed

Expand Down
41 changes: 38 additions & 3 deletions src/engine/Collision/BoundingBox.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Vector } from '../Math/vector';
import { vec, Vector } from '../Math/vector';
import { Ray } from '../Math/ray';
import { Color } from '../Color';
import { Side } from './Side';
Expand Down Expand Up @@ -140,14 +140,39 @@ export class BoundingBox {
return BoundingBox.fromPoints(points);
}

/**
* Scale a bounding box by a scale factor, optionally provide a point
* @param scale
* @param point
*/
public scale(scale: Vector, point: Vector = Vector.Zero): BoundingBox {
const shifted = this.translate(point);
return new BoundingBox(shifted.left * scale.x, shifted.top * scale.y, shifted.right * scale.x, shifted.bottom * scale.y);
}

/**
* Transform the axis aligned bounding box by a [[Matrix]], producing a new axis aligned bounding box
* @param matrix
*/
public transform(matrix: Matrix) {
const points = this.getPoints().map((p) => matrix.multiply(p));
return BoundingBox.fromPoints(points);
const matFirstColumn = vec(matrix.data[0], matrix.data[1]);
const xa = matFirstColumn.scale(this.left);
const xb = matFirstColumn.scale(this.right);

const matSecondColumn = vec(matrix.data[4], matrix.data[5]);
const ya = matSecondColumn.scale(this.top);
const yb = matSecondColumn.scale(this.bottom);

const matrixPos = matrix.getPosition();
const topLeft = Vector.min(xa, xb).add(Vector.min(ya, yb)).add(matrixPos);
const bottomRight = Vector.max(xa, xb).add(Vector.max(ya, yb)).add(matrixPos);

return new BoundingBox({
left: topLeft.x,
top: topLeft.y,
right: bottomRight.x,
bottom: bottomRight.y
});
}

/**
Expand Down Expand Up @@ -257,6 +282,16 @@ export class BoundingBox {
return new Vector(this.width, this.height);
}

/**
* Returns true if the bounding boxes overlap.
* @param other
*/
public overlaps(other: BoundingBox): boolean {
const totalBoundingBox = this.combine(other);
return totalBoundingBox.width < other.width + this.width &&
totalBoundingBox.height < other.height + this.height;
}

/**
* Test wether this bounding box intersects with another returning
* the intersection vector that can be used to resolve the collision. If there
Expand Down
8 changes: 8 additions & 0 deletions src/engine/Math/vector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ export class Vector implements Clonable<Vector> {
return Math.sqrt(Math.pow(vec1.x - vec2.x, 2) + Math.pow(vec1.y - vec2.y, 2));
}

public static min(vec1: Vector, vec2: Vector) {
return new Vector(Math.min(vec1.x, vec2.x), Math.min(vec1.y, vec2.y));
}

public static max(vec1: Vector, vec2: Vector) {
return new Vector(Math.max(vec1.x, vec2.x), Math.max(vec1.y, vec2.y));
}

/**
* @param x X component of the Vector
* @param y Y component of the Vector
Expand Down
18 changes: 18 additions & 0 deletions src/spec/AlgebraSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,24 @@ describe('Vectors', () => {

expect(v.toString(2)).toBe('(1.23, 2.35)');
});

it('can find the min between vectors', () => {
const v1 = new ex.Vector(0, 1);
const v2 = new ex.Vector(2, 0);

const sut = ex.Vector.min(v1, v2);

expect(sut).toBeVector(ex.vec(0, 0));
});

it('can find the max between vectors', () => {
const v1 = new ex.Vector(0, 1);
const v2 = new ex.Vector(2, 0);

const sut = ex.Vector.max(v1, v2);

expect(sut).toBeVector(ex.vec(2, 1));
});
});

describe('Rays', () => {
Expand Down
10 changes: 10 additions & 0 deletions src/spec/BoundingBoxSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ function runBoundingBoxTests(creationType: string, createBoundingBox: Function)
expect(bb.contains(new ex.Vector(10, 20))).toBe(true);
});

it('can overlap with other bounding boxes', () => {
const b1 = new ex.BoundingBox({left: 100, right: 110, top: 100, bottom: 110});
const b2 = new ex.BoundingBox(2, 0, 20, 10);
const b3 = new ex.BoundingBox(12, 0, 28, 10);
expect(b2.overlaps(b3)).toBe(true);
expect(b3.overlaps(b2)).toBe(true);
expect(b1.overlaps(b2)).toBe(false);
expect(b1.overlaps(b3)).toBe(false);
});

it('can collide with other bounding boxes', () => {
const b2 = new ex.BoundingBox(2, 0, 20, 10);
const b3 = new ex.BoundingBox(12, 0, 28, 10);
Expand Down

0 comments on commit 7bd8a82

Please sign in to comment.