day 5
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
import {
|
||||
EasyEvent,
|
||||
Physics_internal,
|
||||
UpdateController,
|
||||
} from "@24tools/playable_template";
|
||||
import { Object3D } from "three";
|
||||
import { Body, Box } from "cannon-es";
|
||||
import { PhysicsBody, PhysicsLayer } from "../PhysicsC";
|
||||
|
||||
const PLAYER_RADIUS = 0.3;
|
||||
|
||||
export type TriggerEventPayload = {
|
||||
lootableObject: Object3D;
|
||||
triggerObject: Object3D;
|
||||
playerBody: Body;
|
||||
};
|
||||
|
||||
type TriggerRecord = {
|
||||
lootableObject: Object3D;
|
||||
triggerObject: Object3D;
|
||||
radius: number;
|
||||
position: Body["position"];
|
||||
physicsBody: PhysicsBody;
|
||||
};
|
||||
|
||||
export class PhysicsTriggerC {
|
||||
private static inited = false;
|
||||
private static triggers: TriggerRecord[] = [];
|
||||
private static activeTriggers = new Set<TriggerRecord>();
|
||||
|
||||
static onTriggerEnter = new EasyEvent<TriggerEventPayload>();
|
||||
static onTriggerExit = new EasyEvent<TriggerEventPayload>();
|
||||
|
||||
static init() {
|
||||
if (this.inited) return;
|
||||
this.inited = true;
|
||||
|
||||
UpdateController.Instance.onUpdate.addDelegate(() => this.update());
|
||||
}
|
||||
|
||||
static register(triggerObject: Object3D, lootableObject: Object3D) {
|
||||
const physicsBody = new PhysicsBody(
|
||||
triggerObject,
|
||||
true,
|
||||
0,
|
||||
PhysicsLayer.Trigger,
|
||||
PhysicsLayer.Player,
|
||||
);
|
||||
|
||||
const body = physicsBody.getPhysicsBody();
|
||||
body.allowSleep = false;
|
||||
|
||||
const shape = body.shapes[0] as Box;
|
||||
const halfExtents = shape.halfExtents;
|
||||
|
||||
this.triggers.push({
|
||||
lootableObject,
|
||||
triggerObject,
|
||||
radius: Math.max(halfExtents.x, halfExtents.y, halfExtents.z),
|
||||
position: body.position,
|
||||
physicsBody,
|
||||
});
|
||||
}
|
||||
|
||||
static unregister(lootableObject: Object3D) {
|
||||
this.triggers = this.triggers.filter((record) => {
|
||||
if (record.lootableObject !== lootableObject) return true;
|
||||
|
||||
record.physicsBody.destroy();
|
||||
this.activeTriggers.delete(record);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private static update() {
|
||||
const playerBody = Physics_internal.physicsWorld?.bodies.find(
|
||||
(body) => body.collisionFilterGroup === PhysicsLayer.Player,
|
||||
);
|
||||
if (!playerBody) return;
|
||||
|
||||
for (const trigger of this.triggers) {
|
||||
const dx = playerBody.position.x - trigger.position.x;
|
||||
const dy = playerBody.position.y - trigger.position.y;
|
||||
const dz = playerBody.position.z - trigger.position.z;
|
||||
const distanceSq = dx * dx + dy * dy + dz * dz;
|
||||
const isInside = distanceSq <= (trigger.radius + PLAYER_RADIUS) ** 2;
|
||||
const wasInside = this.activeTriggers.has(trigger);
|
||||
|
||||
if (isInside === wasInside) continue;
|
||||
|
||||
const payload: TriggerEventPayload = {
|
||||
lootableObject: trigger.lootableObject,
|
||||
triggerObject: trigger.triggerObject,
|
||||
playerBody,
|
||||
};
|
||||
|
||||
if (isInside) {
|
||||
this.activeTriggers.add(trigger);
|
||||
this.onTriggerEnter.Invoke(payload);
|
||||
console.log("[Gather Enter]", trigger.lootableObject.name);
|
||||
} else {
|
||||
this.activeTriggers.delete(trigger);
|
||||
this.onTriggerExit.Invoke(payload);
|
||||
console.log("[Gather Exit]", trigger.lootableObject.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user