Files
js-dev-onboarding-24-play/src/controllers/PhysicsC.ts
T
24Play-Mykyta-Slobodianiuk 78d85c3799 feat:
-Add UI (Health bars, Resources UI, HUD Interface, Weapon U, Zoombie Invasion progress Indicator)

-Refactor code structure for improved readability and maintainability
2026-06-08 18:33:28 +03:00

73 lines
2.3 KiB
TypeScript

import { Physics_internal } from "@24tools/playable_template";
import { Box3, Object3D, Vector3 } from "three";
import { Body, Box, Quaternion, Sphere, Vec3 } from "cannon-es";
// Collision layers. Each body has a `group` (what it IS) and a `mask` (what it
// COLLIDES WITH); two bodies interact only if each one's group is in the other's
// mask. Values are bit flags so masks can be OR-combined (e.g. Wall | Trigger).
export enum PhysicsLayer {
Player = 1,
Wall = 2,
Trigger = 4,
Enemy = 8,
}
/**
* Wraps a three.js object in a cannon-es rigid body. The shape is derived from
* the object: the player gets a Sphere (rolls smoothly along walls/floor),
* everything else gets a Box sized to the object's bounding box.
*/
export class PhysicsBody {
private body: Body;
constructor(
object: Object3D,
isTrigger: boolean,
mass: number,
collisionGroup: PhysicsLayer,
collisionMask: PhysicsLayer,
sphereRadius = 0.3,
) {
const isPlayer = collisionGroup === PhysicsLayer.Player;
// Measure the bounding box with rotation temporarily zeroed, so the box
// half-extents match the object's un-rotated size; the body's own
// quaternion (set below) then applies the real orientation.
const savedRotation = object.quaternion.clone();
object.quaternion.copy(new Quaternion());
const size = new Box3().setFromObject(object).getSize(new Vector3());
object.quaternion.copy(savedRotation);
this.body = new Body({
isTrigger,
mass,
shape: isPlayer
? new Sphere(sphereRadius)
: new Box(new Vec3(size.x / 2, size.y / 2, size.z / 2)),
collisionFilterGroup: collisionGroup,
collisionFilterMask: collisionMask,
});
const worldPos = object.getWorldPosition(new Vector3());
this.body.position.set(worldPos.x, worldPos.y, worldPos.z);
this.body.quaternion.setFromEuler(
object.rotation.x,
object.rotation.y,
object.rotation.z,
"XYZ",
);
Physics_internal.physicsWorld?.addBody(this.body);
}
/** The underlying cannon body (for direct velocity/position control). */
getPhysicsBody(): Body {
return this.body;
}
/** Remove the body from the physics world (e.g. when a crate breaks). */
destroy() {
Physics_internal.physicsWorld?.removeBody(this.body);
}
}