import type { Shape } from '../shapes/Shape' import { Vec3 } from '../math/Vec3' import { Box } from '../shapes/Box' import { Sphere } from '../shapes/Sphere' import { Body } from '../objects/Body' import { World } from '../world/World' import { ArrayCollisionMatrix } from '../collision/ArrayCollisionMatrix' import { ObjectCollisionMatrix } from '../collision/ObjectCollisionMatrix' import { RaycastResult } from '../collision/RaycastResult' import { testCollisionMatrix } from '../../test/helpers' describe('World', () => { test('clearForces', () => { const world = new World() const body = new Body() world.addBody(body) body.force.set(1, 2, 3) body.torque.set(4, 5, 6) world.clearForces() expect(body.force.almostEquals(new Vec3(0, 0, 0))).toBe(true) expect(body.torque.almostEquals(new Vec3(0, 0, 0))).toBe(true) }) test('rayTestBox', () => { const world = new World() const body = new Body() body.addShape(new Box(new Vec3(1, 1, 1))) world.addBody(body) const from = new Vec3(-10, 0, 0) const to = new Vec3(10, 0, 0) const result = new RaycastResult() world.rayTest(from, to, result) expect(result.hasHit).toBe(true) }) test('rayTestSphere', () => { const world = new World() const body = new Body() body.addShape(new Sphere(1)) world.addBody(body) const from = new Vec3(-10, 0, 0) const to = new Vec3(10, 0, 0) const result = new RaycastResult() world.rayTest(from, to, result) expect(result.hasHit).toBe(true) }) test('raycastClosest: single', () => { const world = new World() const body = new Body({ shape: new Sphere(1), }) world.addBody(body) const from = new Vec3(-10, 0, 0) const to = new Vec3(10, 0, 0) const result = new RaycastResult() world.raycastClosest(from, to, {}, result) expect(result.hasHit).toBe(true) expect(result.body).toEqual(body) expect(result.shape).toBe(body.shapes[0]) }) test('raycastClosest: order', () => { const world = new World() const bodyA = new Body({ shape: new Sphere(1), position: new Vec3(-1, 0, 0) }) const bodyB = new Body({ shape: new Sphere(1), position: new Vec3(1, 0, 0) }) world.addBody(bodyA) world.addBody(bodyB) const from = new Vec3(-10, 0, 0) const to = new Vec3(10, 0, 0) let result = new RaycastResult() world.raycastClosest(from, to, {}, result) expect(result.hasHit).toBe(true) expect(result.body).toBe(bodyA) expect(result.shape).toBe(bodyA.shapes[0]) from.set(10, 0, 0) to.set(-10, 0, 0) result = new RaycastResult() world.raycastClosest(from, to, {}, result) expect(result.hasHit).toBe(true) expect(result.body).toBe(bodyB) expect(result.shape).toBe(bodyB.shapes[0]) }) test('raycastAll: simple', () => { const world = new World() const body = new Body({ shape: new Sphere(1) }) world.addBody(body) const from = new Vec3(-10, 0, 0) const to = new Vec3(10, 0, 0) let numResults = 0 const returnVal = world.raycastAll(from, to, {}, function (result) { expect(result.hasHit).toBe(true) expect(result.body).toBe(body) expect(result.shape).toBe(result.body?.shapes[0]) numResults++ }) expect(numResults).toBe(2) expect(returnVal).toBe(true) }) test('raycastAll: two spheres', () => { const world = new World() const body = new Body({ shape: new Sphere(1) }) world.addBody(body) const body2 = new Body({ shape: new Sphere(1) }) world.addBody(body2) const from = new Vec3(-10, 0, 0) const to = new Vec3(10, 0, 0) let hasHit = false let numResults = 0 world.raycastAll(from, to, {}, function (result) { hasHit = result.hasHit numResults++ }) expect(hasHit).toBe(true) expect(numResults).toBe(4) }) test('raycastAll: skipBackfaces', () => { const world = new World() const body = new Body({ shape: new Sphere(1) }) world.addBody(body) let numResults = 0 world.raycastAll(new Vec3(-10, 0, 0), new Vec3(10, 0, 0), { skipBackfaces: true }, function (result) { expect(result.hasHit).toBe(true) expect(result.body).toBe(body) expect(result.shape).toBe(result.body?.shapes[0]) numResults++ }) expect(numResults).toBe(1) }) test('raycastAll: collisionFilters', () => { const world = new World() const body = new Body({ shape: new Sphere(1), }) world.addBody(body) body.collisionFilterGroup = 2 body.collisionFilterMask = 2 let numResults = 0 world.raycastAll( new Vec3(-10, 0, 0), new Vec3(10, 0, 0), { collisionFilterGroup: 2, collisionFilterMask: 2, }, function () { numResults++ } ) expect(numResults).toBe(2) numResults = 0 world.raycastAll( new Vec3(-10, 0, 0), new Vec3(10, 0, 0), { collisionFilterGroup: 1, collisionFilterMask: 1, }, function () { numResults++ } ) expect(numResults).toBe(0) // should use collision groups! }) test('raycastAny', () => { const world = new World() world.addBody(new Body({ shape: new Sphere(1) })) const from = new Vec3(-10, 0, 0) const to = new Vec3(10, 0, 0) const result = new RaycastResult() world.raycastAny(from, to, {}, result) expect(result.hasHit).toBe(true) }) test('using ArrayCollisionMatrix', () => { testCollisionMatrix(ArrayCollisionMatrix) }) test('using ObjectCollisionMatrix', () => { testCollisionMatrix(ObjectCollisionMatrix) }) })