collider2d
Version:
A 2D collision checker for modern JavaScript games.
454 lines (353 loc) • 15.3 kB
JavaScript
'use strict'
const chai = require('chai');
const { Vector, Box, Circle, Polygon, Collider2d } = require('../build/index.js');
const collider2d = new Collider2d();
describe('Vector Scaling', () => {
it('should scale by zero properly', () => {
const v1 = new Vector(5, 5);
v1.scale(10, 10);
chai.expect(v1.x).to.equal(50);
chai.expect(v1.y).to.equal(50);
v1.scale(0, 1);
chai.expect(v1.x).to.equal(0);
chai.expect(v1.y).to.equal(50);
v1.scale(1, 0);
chai.expect(v1.x).to.equal(0);
chai.expect(v1.y).to.equal(0);
});
});
describe("Polygon Centroids", () => {
describe("Generic Points", () => {
it("should return the generic points of the Polygon", () => {
const polygon = new Polygon(new Vector(100, 100), [
new Vector(0, 0),
new Vector(200, 0),
new Vector(100, 200),
new Vector(0, 200),
]);
chai.expect(polygon.pointsGeneric).to.deep.equal([0, 0, 200, 0, 100, 200, 0, 200]);
});
});
describe("Centroids", () => {
it("should calculate the correct value for a square", () => {
const polygon = new Polygon(
new Vector(0, 0), [
new Vector(0, 0),
new Vector(40, 0),
new Vector(40, 40),
new Vector(0, 40)
]);
const c = polygon.getCentroid();
chai.expect(c.x).to.equal(20);
chai.expect(c.y).to.equal(20);
});
it("should calculate the correct value for a triangle", () => {
const polygon = new Polygon(
new Vector(0, 0), [
new Vector(0, 0),
new Vector(100, 0),
new Vector(50, 99)
]);
const c = polygon.getCentroid();
chai.expect(c.x).to.equal(50);
chai.expect(c.y).to.equal(33);
});
});
});
describe("Collision", () => {
it("testCircleCircle", () => {
const circle1 = new Circle(new Vector(0, 0), 20);
const circle2 = new Circle(new Vector(30, 0), 20);
// const response = collider2d.response();
// Test collision = true - without details.
const collided = collider2d.testCircleCircle(circle1, circle2);
chai.expect(collided).to.be.true;
// Test collision = true - with details.
const collidedDetails = collider2d.testCircleCircle(circle1, circle2, true);
chai.expect(collidedDetails).to.not.be.false;
chai.expect(collidedDetails.overlap).to.equal(10);
chai.expect(collidedDetails.overlapV.x).to.equal(10);
chai.expect(collidedDetails.overlapV.y).to.equal(0);
// Test collision = false - without details - after changing offset.
circle1.offset = new Vector(-10, -10);
const collidedAfterOffsetChange = collider2d.testCircleCircle(circle1, circle2);
chai.expect(collidedAfterOffsetChange).to.be.false;
// let collided = collider2d.testCircleCircle(circle1, circle2, response);
// let collided = collider2d.testCircleCircle(circle1, circle2, true);
// chai.expect(collided).to.not.be.null;
// chai.expect(response.overlap).to.equal(10);
// chai.expect(response.overlapV.x).to.equal(10) && chai.expect(response.overlapV.y).to.equal(0);
// circle1.offset = new Vector(-10, -10);
// collided = collider2d.testCircleCircle(circle1, circle2, response);
// chai.expect(collided).to.be.false;
});
it("testPolygonCircle", () => {
const circle = new Circle(new Vector(50, 50), 20);
const polygon = new Polygon(new Vector(0, 0), [
new Vector(0, 0),
new Vector(40, 0),
new Vector(40, 40),
new Vector(0, 40)
]);
// Test collision = true - no details
const collided = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collided).to.be.true;
// Test collision = true - details
const collidedDetails = collider2d.testPolygonCircle(polygon, circle, true);
chai.expect(collidedDetails.overlap.toFixed(2)).to.equal('5.86');
chai.expect(collidedDetails.overlapV.x.toFixed(2)).to.equal('4.14') && chai.expect(collidedDetails.overlapV.y.toFixed(2)).to.equal('4.14');
// Test collision = false - no details - after offset change
circle.offset = new Vector(10, 10);
const collidedAfterOffsetChange = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collidedAfterOffsetChange).to.be.false;
});
it('testPolygonCircle - line - not collide', () => {
const circle = new Circle(new Vector(50, 50), 20);
const polygon = new Box(new Vector(1000, 1000), 100, 0).toPolygon();
// Test collision = false - no details
const collided = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collided).to.be.false;
});
it('testPolygonCircle - line - collide', () => {
const circle = new Circle(new Vector(50, 50), 20);
const polygon = new Box(new Vector(50, 50), 100, 0).toPolygon();
// Test collision = true - no details
const collided = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collided).to.be.true;
// Test collision = true - with details
const collidedDetails = collider2d.testPolygonCircle(polygon, circle, true);
chai.expect(collidedDetails.overlap.toFixed(2)).to.equal('20.00');
});
it("testPolygonPolygon", () => {
const polygon1 = new Polygon(new Vector(0, 0), [
new Vector(0, 0),
new Vector(40, 0),
new Vector(40, 40),
new Vector(0, 40)
]);
const polygon2 = new Polygon(new Vector(30, 0), [
new Vector(0, 0),
new Vector(30, 0),
new Vector(0, 30)
]);
// Test collision = true - no details
const collided = collider2d.testPolygonPolygon(polygon1, polygon2);
chai.expect(collided).to.be.true;
// Test collision = true - with details
const collidedDetails = collider2d.testPolygonPolygon(polygon1, polygon2, true);
chai.expect(collidedDetails.overlap).to.equal(10);
chai.expect(collidedDetails.overlapV.x).to.equal(10);
chai.expect(collidedDetails.overlapV.y).to.equal(0);
});
});
describe("No collision", () => {
it("testPolygonPolygon", () => {
const box1 = new Box(new Vector(0, 0), 20, 20).toPolygon();
const box2 = new Box(new Vector(100, 100), 20, 20).toPolygon();
// Test collision = false - no details
const collided = collider2d.testPolygonPolygon(box1, box2);
chai.expect(collided).to.be.false;
});
});
describe("Point Collisions", () => {
it("pointInCircle", () => {
const circle = new Circle(new Vector(100, 100), 20);
// Test collision = false
const collisionFalse = collider2d.pointInCircle(new Vector(0, 0), circle)
chai.expect(collisionFalse).to.be.false;
// Test collision = true
const collisionTrue = collider2d.pointInCircle(new Vector(110, 110), circle);
chai.expect(collisionTrue).to.be.true;
// Test collision = false - after offset changed.
circle.offset = new Vector(-10, -10);
const collisionAfterOffsetChange = collider2d.pointInCircle(new Vector(110, 110), circle);
chai.expect(collisionAfterOffsetChange).to.be.false;
});
it("pointInPolygon", () => {
const triangle = new Polygon(new Vector(30, 0), [
new Vector(0, 0),
new Vector(30, 0),
new Vector(0, 30)
]);
// Test collision = false
const collisionFalse = collider2d.pointInPolygon(new Vector(0, 0), triangle);
chai.expect(collisionFalse).to.be.false;
// Test collision = true
const collisionTrue = collider2d.pointInPolygon(new Vector(35, 5), triangle);
chai.expect(collisionTrue).to.be.true;
});
it("pointInPolygon (small)", () => {
const v1 = new Vector(1, 1.1);
const p1 = new Polygon(new Vector(0, 0), [
new Vector(2, 1),
new Vector(2, 2),
new Vector(1, 3),
new Vector(0, 2),
new Vector(0, 1),
new Vector(1, 0)
]);
// Test collision = true
const collision = collider2d.pointInPolygon(v1, p1);
chai.expect(collision).to.be.true;
});
});
describe('Collision - After moving from initial position', () => {
it("testCircleCircle - should not detect a collision after a circle is moved from collision range", () => {
const circle1 = new Circle(new Vector(0, 0), 20);
const circle2 = new Circle(new Vector(10, 0), 20);
// Test collision = true - without details.
const collided = collider2d.testCircleCircle(circle1, circle2);
chai.expect(collided).to.be.true;
circle2.translate(40, 50);
// Test collision = false - moved from collision range.
const collidedAfterMove = collider2d.testCircleCircle(circle1, circle2);
chai.expect(collidedAfterMove).to.be.false;
});
it("testCircleCircle - should detect a collision after a circle is moved to collision range", () => {
const circle1 = new Circle(new Vector(0, 0), 20);
const circle2 = new Circle(new Vector(10, 100), 20);
// Test collision = false.
const collided = collider2d.testCircleCircle(circle1, circle2);
chai.expect(collided).to.be.false;
circle2.translate(-5, -90);
// Test collision = true - moved to collision range.
const collidedAfterMove = collider2d.testCircleCircle(circle1, circle2);
chai.expect(collidedAfterMove).to.be.true;
});
it("testPolygonCircle - should not detect a collision after the polygon is moved - (x, y) greater", () => {
const circle = new Circle(new Vector(50, 50), 20);
const polygon = new Polygon(new Vector(10, 10), [
new Vector(0, 0),
new Vector(40, 0),
new Vector(40, 40),
new Vector(0, 40)
]);
// Test collision = true - no details
const collided = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collided).to.be.true;
polygon.translate(200, 300);
// Test collision = false - after moving polygon to (200, 300);
const collidedAfterMoving = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collidedAfterMoving).to.be.false;
});
it("testPolygonCircle - should not detect a collision after the polygon is moved - (x, y) less", () => {
const circle = new Circle(new Vector(50, 50), 20);
const polygon = new Polygon(new Vector(10, 10), [
new Vector(0, 0),
new Vector(40, 0),
new Vector(40, 40),
new Vector(0, 40)
]);
// Test collision = true - no details
const collided = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collided).to.be.true;
polygon.translate(-200, -150);
// Test collision = false - after moving polygon to (-200, -150);
const collidedAfterMoving = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collidedAfterMoving).to.be.false;
});
it("testPolygonCircle - should detect a collision after the polygon is moved - (x, y) greater", () => {
const circle = new Circle(new Vector(50, 50), 20);
const polygon = new Polygon(new Vector(-150, -125), [
new Vector(0, 0),
new Vector(40, 0),
new Vector(40, 40),
new Vector(0, 40)
]);
// Test collision = false
const collided = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collided).to.be.false;
polygon.translate(180, 150);
// Test collision = true - after moving polygon to (30, 25);
const collidedAfterMoving = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collidedAfterMoving).to.be.true;
});
it("testPolygonCircle - should detect a collision after the polygon is moved - (x, y) less", () => {
const circle = new Circle(new Vector(50, 50), 20);
const polygon = new Polygon(new Vector(200, 300), [
new Vector(0, 0),
new Vector(40, 0),
new Vector(40, 40),
new Vector(0, 40)
]);
// Test collision = false
const collided = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collided).to.be.false;
polygon.translate(-170, -275);
// Test collision = true - after moving polygon to (30, 25);
const collidedAfterMoving = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collidedAfterMoving).to.be.true;
});
it("testPolygonCircle - should not detect a collision after the circle is moved", () => {
const circle = new Circle(new Vector(50, 50), 20);
const polygon = new Polygon(new Vector(25, 25), [
new Vector(0, 0),
new Vector(40, 0),
new Vector(40, 40),
new Vector(0, 40)
]);
// Test collision = false
const collided = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collided).to.be.true;
circle.translate(200, 300);
// Test collision = true - after moving polygon to (30, 25);
const collidedAfterMoving = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collidedAfterMoving).to.be.false;
});
it("testPolygonCircle - should detect a collision after the circle is moved", () => {
const circle = new Circle(new Vector(200, 150), 20);
const polygon = new Polygon(new Vector(0, 0), [
new Vector(0, 0),
new Vector(40, 0),
new Vector(40, 40),
new Vector(0, 40)
]);
// Test collision = false
const collided = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collided).to.be.false;
circle.translate(-150, -100);
// Test collision = true - after moving circle to (50, 50).
const collidedAfterMoving = collider2d.testPolygonCircle(polygon, circle);
chai.expect(collidedAfterMoving).to.be.true;
});
it("testPolygonPolygon - should not detect a collision after the polygon is moved - (x, y) greater", () => {
const polygon1 = new Polygon(new Vector(0, 0), [
new Vector(0, 0),
new Vector(40, 0),
new Vector(40, 40),
new Vector(0, 40)
]);
const polygon2 = new Polygon(new Vector(30, 0), [
new Vector(0, 0),
new Vector(30, 0),
new Vector(0, 30)
]);
// Test collision = true.
const collided = collider2d.testPolygonPolygon(polygon1, polygon2);
chai.expect(collided).to.be.true;
// Test collision = false - after moving polygon.
polygon2.translate(90, 150);
const collidedAfterMoving = collider2d.testPolygonPolygon(polygon1, polygon2);
chai.expect(collidedAfterMoving).to.be.false;
});
it("testPolygonPolygon - should not detect a collision after the polygon is moved - (x, y) less", () => {
const polygon1 = new Polygon(new Vector(0, 0), [
new Vector(0, 0),
new Vector(40, 0),
new Vector(40, 40),
new Vector(0, 40)
]);
const polygon2 = new Polygon(new Vector(140, 150), [
new Vector(0, 0),
new Vector(30, 0),
new Vector(0, 30)
]);
// Test collision = false
const collided = collider2d.testPolygonPolygon(polygon1, polygon2);
chai.expect(collided).to.be.false;
// Test collision = true - after moving polygon.
polygon2.translate(-110, -150);
const collidedAfterMoving = collider2d.testPolygonPolygon(polygon1, polygon2);
chai.expect(collidedAfterMoving).to.be.true;
});
});