feat:
-Add UI (Health bars, Resources UI, HUD Interface, Weapon U, Zoombie Invasion progress Indicator) -Refactor code structure for improved readability and maintainability
This commit is contained in:
+37
-94
@@ -1,11 +1,10 @@
|
||||
import {
|
||||
Delegate,
|
||||
Physics_internal,
|
||||
UpdateController,
|
||||
} from "@24tools/playable_template";
|
||||
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,
|
||||
@@ -13,117 +12,61 @@ export enum PhysicsLayer {
|
||||
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;
|
||||
private pair: PhysicsObjPair | null = null;
|
||||
|
||||
constructor(
|
||||
threeObj: Object3D,
|
||||
trigger: boolean,
|
||||
object: Object3D,
|
||||
isTrigger: boolean,
|
||||
mass: number,
|
||||
col_group: PhysicsLayer,
|
||||
col_mask: PhysicsLayer,
|
||||
player_sphere: number = 0.3
|
||||
collisionGroup: PhysicsLayer,
|
||||
collisionMask: PhysicsLayer,
|
||||
sphereRadius = 0.3,
|
||||
) {
|
||||
let isPlayer = col_group === PhysicsLayer.Player;
|
||||
const isPlayer = collisionGroup === PhysicsLayer.Player;
|
||||
|
||||
let oldQuaternion = threeObj.quaternion.clone();
|
||||
|
||||
let nullQuaternion = new Quaternion();
|
||||
threeObj.quaternion.copy(nullQuaternion);
|
||||
|
||||
let bbox = new Box3().setFromObject(threeObj);
|
||||
|
||||
let size = new Vector3();
|
||||
bbox.getSize(size);
|
||||
|
||||
// if you need custom size
|
||||
// if (col_group === PhysicsLayer.wall) {
|
||||
// size.x = size.z = 1;
|
||||
// size.y = 1;
|
||||
// }
|
||||
|
||||
threeObj.quaternion.copy(oldQuaternion);
|
||||
// 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: trigger,
|
||||
mass: mass,
|
||||
//shape: shape,
|
||||
isTrigger,
|
||||
mass,
|
||||
shape: isPlayer
|
||||
? new Sphere(player_sphere)
|
||||
? new Sphere(sphereRadius)
|
||||
: new Box(new Vec3(size.x / 2, size.y / 2, size.z / 2)),
|
||||
collisionFilterGroup: col_group,
|
||||
collisionFilterMask: col_mask,
|
||||
collisionFilterGroup: collisionGroup,
|
||||
collisionFilterMask: collisionMask,
|
||||
});
|
||||
|
||||
let worldPos = threeObj.getWorldPosition(new Vector3());
|
||||
|
||||
const worldPos = object.getWorldPosition(new Vector3());
|
||||
this.body.position.set(worldPos.x, worldPos.y, worldPos.z);
|
||||
|
||||
this.body.quaternion.setFromEuler(
|
||||
threeObj.rotation.x,
|
||||
threeObj.rotation.y,
|
||||
threeObj.rotation.z,
|
||||
"XYZ"
|
||||
object.rotation.x,
|
||||
object.rotation.y,
|
||||
object.rotation.z,
|
||||
"XYZ",
|
||||
);
|
||||
|
||||
// if you need sync three obj and physics body
|
||||
// if (isEnemy) {
|
||||
// let pair = new PhysicsObjPair(threeObj, this.body);
|
||||
// PhysicsC_Instance.addPhysicsPair(pair);
|
||||
|
||||
// this.pair = pair;
|
||||
// }
|
||||
|
||||
Physics_internal.physicsWorld &&
|
||||
Physics_internal.physicsWorld.addBody(this.body);
|
||||
|
||||
return this;
|
||||
Physics_internal.physicsWorld?.addBody(this.body);
|
||||
}
|
||||
|
||||
disablePhysicsPair() {
|
||||
if (this.pair) {
|
||||
this.pair.destroyed = true;
|
||||
}
|
||||
}
|
||||
|
||||
getPhysicsBody() {
|
||||
/** 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() {
|
||||
if (!Physics_internal.physicsWorld) return;
|
||||
|
||||
Physics_internal.physicsWorld.removeBody(this.body);
|
||||
|
||||
(this.body as any) = null;
|
||||
}
|
||||
}
|
||||
|
||||
export class PhysicsObjPair {
|
||||
threeObj: Object3D;
|
||||
physicsObj: Body;
|
||||
destroyed: boolean;
|
||||
delegateId: null | Delegate<number>;
|
||||
|
||||
constructor(threeObj: Object3D, physicsObj: Body) {
|
||||
this.threeObj = threeObj;
|
||||
this.physicsObj = physicsObj;
|
||||
this.destroyed = false;
|
||||
|
||||
this.delegateId = UpdateController.Instance.onUpdate.addDelegate(() => {
|
||||
this.update();
|
||||
});
|
||||
}
|
||||
|
||||
update() {
|
||||
if (this.destroyed) return;
|
||||
|
||||
if (this.threeObj && this.physicsObj) {
|
||||
// @ts-ignore
|
||||
this.threeObj.position.copy(this.physicsObj.position);
|
||||
// @ts-ignore
|
||||
this.threeObj.quaternion.copy(this.physicsObj.quaternion);
|
||||
}
|
||||
Physics_internal.physicsWorld?.removeBody(this.body);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user