This commit is contained in:
Vasyl Kazakov
2026-05-29 18:01:05 +03:00
parent 2633be60a1
commit 6363396f84
20 changed files with 978 additions and 81 deletions
+105 -9
View File
@@ -1,6 +1,12 @@
import { Object3D } from "three";
import { Box3, BoxGeometry, Mesh, Object3D, Vector3 } from "three";
import { ThreeC } from "../ThreeC";
import { PhysicsBody, PhysicsLayer } from "../PhysicsC";
import { PhysicsTriggerC } from "./PhysicsTriggerC";
import { PropC } from "./PropC";
import { resolvePropType } from "../Resources/PropDropTable";
const MAP_PHYSICS_LAYERS = ["Colliders", "Lootable"];
const GATHER_TRIGGER_PADDING = 0.2;
export class Map {
static Init() {
@@ -14,19 +20,109 @@ export class Map {
ThreeC.setShadowsStateForChildren(mapObject, true, true);
ThreeC.addToScene(mapObject);
const colliders = mapObject.getObjectByName("Colliders");
if (colliders) {
colliders.visible = false;
this.buildColliders(colliders);
PhysicsTriggerC.init();
this.buildPhysics(mapObject);
}
private static buildPhysics(mapObject: Object3D) {
for (const layerName of MAP_PHYSICS_LAYERS) {
const layer = mapObject.getObjectByName(layerName);
if (!layer) {
console.warn(`Map physics layer not found: ${layerName}`);
continue;
}
if (layerName === "Colliders") {
layer.visible = false;
this.addWallPhysics(layer);
continue;
}
layer.children.forEach((lootableObject) => {
this.setupLootableObject(lootableObject);
});
}
}
private static buildColliders(collidersRoot: Object3D) {
collidersRoot.traverse((child) => {
if (child === collidersRoot) return;
if ((child as any).isMesh) {
private static addWallPhysics(root: Object3D) {
root.traverse((child) => {
if (child === root) return;
if ((child as Mesh).isMesh) {
new PhysicsBody(child, false, 0, PhysicsLayer.Wall, PhysicsLayer.Player);
}
});
}
private static setupLootableObject(lootableObject: Object3D) {
const propType = resolvePropType(lootableObject.name);
const prop = new PropC(lootableObject, propType);
const colliderMesh = this.findMesh(lootableObject, (name) => name.includes("collider"));
const visualMeshes = this.getVisualMeshes(lootableObject);
if (colliderMesh) {
colliderMesh.visible = false;
prop.addWallBody(
new PhysicsBody(colliderMesh, false, 0, PhysicsLayer.Wall, PhysicsLayer.Player),
);
} else {
visualMeshes.forEach((mesh) => {
prop.addWallBody(
new PhysicsBody(mesh, false, 0, PhysicsLayer.Wall, PhysicsLayer.Player),
);
});
}
PhysicsTriggerC.register(this.createGatherTrigger(lootableObject), lootableObject);
}
private static findMesh(
root: Object3D,
matcher: (name: string) => boolean,
): Mesh | null {
let found: Mesh | null = null;
root.traverse((child) => {
if (found) return;
if ((child as Mesh).isMesh && matcher(child.name.toLowerCase())) {
found = child as Mesh;
}
});
return found;
}
private static getVisualMeshes(root: Object3D): Mesh[] {
const visualMeshes: Mesh[] = [];
root.traverse((child) => {
if (!(child as Mesh).isMesh) return;
const name = child.name.toLowerCase();
if (name.includes("collider") || name.includes("trigger") || name.includes("gathertrigger")) return;
visualMeshes.push(child as Mesh);
});
return visualMeshes;
}
private static createGatherTrigger(lootableObject: Object3D): Mesh {
lootableObject.updateWorldMatrix(true, true);
const size = new Vector3();
new Box3().setFromObject(lootableObject).getSize(size);
const triggerMesh = new Mesh(
new BoxGeometry(
size.x + GATHER_TRIGGER_PADDING * 2,
size.y + GATHER_TRIGGER_PADDING * 2,
size.z + GATHER_TRIGGER_PADDING * 2,
),
);
triggerMesh.visible = false;
triggerMesh.name = "GatherTrigger";
lootableObject.add(triggerMesh);
return triggerMesh;
}
}