UNPKG

threefiz

Version:

Implementation of a physics engine based on the [Three.js](https://github.com/mrdoob/three.js) library.

129 lines (112 loc) 3.53 kB
import Cuboid from "./Cuboid"; import { Scene, Vector3 } from "three"; import World from "./World"; import RigidBody, { RigidBodyProps } from "./RigidBody"; import Sphere from "./Sphere"; import AABBTree from "./AABBTree/AABBTree"; const v = new Vector3(); const tree = new AABBTree(); let RESULTS: Uint16Array<ArrayBuffer>; type Props = { scene: Scene; timeStep: number; gravity: Vector3; }; class ThreeFiz { private dT: number = 0.0; private accumulator: number = 0.0; private lastTicks: number = 0.0; objects: RigidBody[] = []; private readonly scene: Scene; private readonly world: World; private isPaused: boolean = false; constructor({ scene = new Scene(), gravity = new Vector3(0, -9.8, 0), }: Partial<Props> = {}) { this.scene = scene; this.world = new World(gravity); document.addEventListener("visibilitychange", this.visibilityChange); } addBox(object: Partial<RigidBodyProps>): void { const newObject = new Cuboid(object); this.objects.push(newObject); this.scene.add(newObject.mesh); newObject.mesh.updateMatrix(); newObject.mesh.updateMatrixWorld(); newObject.updateAABB(); newObject.updateCollider(); tree.insert( newObject.aabb, this.objects.length - 1, `${newObject.constructor.name}${this.objects.length - 1}` ); newObject.mesh.position.copy(newObject.getPosition(v)); } addSphere(object: Partial<RigidBodyProps>): void { const newObject = new Sphere(object); this.objects.push(newObject); this.scene.add(newObject.mesh); newObject.updateAABB(); newObject.updateCollider(); tree.insert( newObject.aabb, this.objects.length - 1, `${newObject.constructor.name}${this.objects.length - 1}` ); newObject.mesh.position.copy(newObject.getPosition(v)); } init(): void { this.lastTicks = Date.now(); this.world.updateObjects(this.objects, tree, 0); const N = this.objects.length; RESULTS = new Uint16Array(N); } setGravity(gravity: Vector3): void { this.world.setGravity(gravity); } private update(dT: number): void { this.world.updateObjects(this.objects, tree, dT); this.detectCollisions(); } pause(): void { this.isPaused = true; } resume(): void { this.isPaused = false; } onCollision(_object1: RigidBody, _object2: RigidBody): void {} private detectCollisions(): void { let objB: RigidBody; let maxResults: number; this.objects.forEach((objA, idx) => { maxResults = tree.query(RESULTS, objA.aabb, idx); for (let i = 0; i < maxResults; i++) { if (idx < RESULTS[i]) { objB = this.objects[RESULTS[i]]; if (!objA.isStatic || !objB.isStatic) { if (objA.intersects(objB)) { objA.resolveCollision(objB); this.onCollision(objA, objB); } } } } }); } visibilityChange = () => { if (!document.hidden) this.lastTicks = Date.now(); }; step(): void { const fixedTimeStep = 0.001; this.accumulator += this.dT; while (this.accumulator >= fixedTimeStep) { if (!this.isPaused) this.update(fixedTimeStep); this.accumulator -= fixedTimeStep; } const currentTime = Date.now(); this.dT = (currentTime - this.lastTicks) / 1000; this.lastTicks = currentTime; } } export default ThreeFiz;