157 lines
7.0 KiB
JavaScript
157 lines
7.0 KiB
JavaScript
import * as THREE from 'three';
|
|
import { state } from '../state.js';
|
|
import wallTextureUrl from '/textures/stone_wall.png';
|
|
import sceneFeatureManager from './SceneFeatureManager.js';
|
|
import { SceneFeature } from './SceneFeature.js';
|
|
const length = 40;
|
|
|
|
export class RoomWalls extends SceneFeature {
|
|
constructor() {
|
|
super();
|
|
sceneFeatureManager.register(this);
|
|
}
|
|
init() {
|
|
const naveWidth = 12;
|
|
const aisleWidth = 6;
|
|
const totalWidth = naveWidth + 2 * aisleWidth;
|
|
|
|
const aisleHeight = 8;
|
|
const naveHeight = 15;
|
|
const roofPeakHeight = 6; // Additional height for the nave's vaulted roof peak
|
|
|
|
// --- Pillar and Arch Dimensions ---
|
|
const pillarSize = 1.0;
|
|
const pillarHeight = aisleHeight;
|
|
const numPillars = 5; // Number of pillars along each side
|
|
const pillarSpacing = length / (numPillars + 1);
|
|
|
|
// --- Materials and Textures ---
|
|
const wallTexture = state.loader.load(wallTextureUrl);
|
|
wallTexture.wrapS = THREE.RepeatWrapping;
|
|
wallTexture.wrapT = THREE.RepeatWrapping;
|
|
|
|
const wallMaterial = new THREE.MeshStandardMaterial({
|
|
map: wallTexture,
|
|
side: THREE.DoubleSide,
|
|
shininess: 5,
|
|
roughness: 0.2,
|
|
metalness: 0.1,
|
|
specular: 0x111111
|
|
});
|
|
|
|
// --- Geometry Definitions ---
|
|
const pillarGeo = new THREE.CylinderGeometry(pillarSize / 2, pillarSize / 2, pillarHeight, 24);
|
|
|
|
// --- Object Creation Functions ---
|
|
const createMesh = (geometry, material, position, rotation = new THREE.Euler()) => {
|
|
const mesh = new THREE.Mesh(geometry, material);
|
|
mesh.position.copy(position);
|
|
mesh.rotation.copy(rotation);
|
|
mesh.castShadow = true;
|
|
mesh.receiveShadow = true;
|
|
state.scene.add(mesh);
|
|
return mesh;
|
|
};
|
|
|
|
// --- Build the Cathedral ---
|
|
|
|
// 1. Back Wall
|
|
const backWallGeo = new THREE.PlaneGeometry(totalWidth, aisleHeight);
|
|
const backWallMat = wallMaterial.clone();
|
|
backWallMat.map = wallTexture.clone();
|
|
backWallMat.map.repeat.set(totalWidth / 4, aisleHeight / 4);
|
|
createMesh(backWallGeo, backWallMat, new THREE.Vector3(0, aisleHeight / 2, -length / 2));
|
|
|
|
// 2. Outer Aisle Walls
|
|
const outerWallGeo = new THREE.PlaneGeometry(length, aisleHeight);
|
|
const outerWallMat = wallMaterial.clone();
|
|
outerWallMat.map = wallTexture.clone();
|
|
outerWallMat.map.repeat.set(length / 4, aisleHeight / 4);
|
|
createMesh(outerWallGeo, outerWallMat, new THREE.Vector3(-totalWidth / 2, aisleHeight / 2, 0), new THREE.Euler(0, Math.PI / 2, 0));
|
|
createMesh(outerWallGeo, outerWallMat, new THREE.Vector3(totalWidth / 2, aisleHeight / 2, 0), new THREE.Euler(0, -Math.PI / 2, 0));
|
|
|
|
// 3. Aisle Roofs (Flat)
|
|
const aisleRoofGeo = new THREE.PlaneGeometry(aisleWidth, length);
|
|
const aisleRoofMat = wallMaterial.clone();
|
|
aisleRoofMat.map = wallTexture.clone();
|
|
aisleRoofMat.map.repeat.set(aisleWidth / 4, length / 4);
|
|
createMesh(aisleRoofGeo, aisleRoofMat, new THREE.Vector3(-naveWidth / 2 - aisleWidth / 2, aisleHeight, 0), new THREE.Euler(-Math.PI / 2, 0, 0));
|
|
createMesh(aisleRoofGeo, aisleRoofMat, new THREE.Vector3(naveWidth / 2 + aisleWidth / 2, aisleHeight, 0), new THREE.Euler(-Math.PI / 2, 0, 0));
|
|
|
|
// 4. Pillars and Arcades
|
|
const arcadeWallHeight = aisleHeight - pillarHeight;
|
|
const arcadeWallGeo = new THREE.PlaneGeometry(pillarSpacing - pillarSize, arcadeWallHeight);
|
|
const arcadeWallMat = wallMaterial.clone();
|
|
arcadeWallMat.map = wallTexture.clone();
|
|
arcadeWallMat.map.repeat.set((pillarSpacing - pillarSize) / 4, arcadeWallHeight / 4);
|
|
|
|
for (let i = 0; i <= numPillars; i++) {
|
|
const z = -length / 2 + pillarSpacing * (i + 0.5);
|
|
// Add wall sections between pillars
|
|
if (i <= numPillars) {
|
|
createMesh(arcadeWallGeo, arcadeWallMat, new THREE.Vector3(-naveWidth / 2 , pillarHeight + arcadeWallHeight / 2, z));
|
|
createMesh(arcadeWallGeo, arcadeWallMat, new THREE.Vector3(naveWidth / 2, pillarHeight + arcadeWallHeight / 2, z));
|
|
}
|
|
|
|
const pillarZ = -length / 2 + pillarSpacing * (i + 1) - pillarSize / 2;
|
|
// Left side pillars
|
|
createMesh(pillarGeo, wallMaterial, new THREE.Vector3(-naveWidth / 2 - pillarSize, pillarHeight / 2, pillarZ));
|
|
// Right side pillars
|
|
createMesh(pillarGeo, wallMaterial, new THREE.Vector3(naveWidth / 2 + pillarSize, pillarHeight / 2, pillarZ));
|
|
}
|
|
|
|
// 5. Clerestory (Upper Nave Walls)
|
|
const clerestoryHeight = naveHeight - aisleHeight;
|
|
const clerestoryGeo = new THREE.PlaneGeometry(length, clerestoryHeight);
|
|
const clerestoryMat = wallMaterial.clone();
|
|
clerestoryMat.map = wallTexture.clone();
|
|
clerestoryMat.map.repeat.set(length / 4, clerestoryHeight / 4);
|
|
// Left and Right Clerestory walls
|
|
createMesh(clerestoryGeo, clerestoryMat, new THREE.Vector3(-naveWidth / 2, aisleHeight + clerestoryHeight / 2, 0), new THREE.Euler(0, - Math.PI / 2, 0));
|
|
createMesh(clerestoryGeo, clerestoryMat, new THREE.Vector3(naveWidth / 2, aisleHeight + clerestoryHeight / 2, 0), new THREE.Euler(0, Math.PI/2, 0));
|
|
|
|
// Upper part of the back wall (for the nave)
|
|
const backClerestoryGeo = new THREE.PlaneGeometry(naveWidth, clerestoryHeight);
|
|
const backClerestoryMat = wallMaterial.clone();
|
|
backClerestoryMat.map = wallTexture.clone();
|
|
backClerestoryMat.map.repeat.set(naveWidth / 4, clerestoryHeight / 4);
|
|
createMesh(backClerestoryGeo, backClerestoryMat, new THREE.Vector3(0, aisleHeight + clerestoryHeight / 2, -length / 2));
|
|
|
|
// 6. Nave's Vaulted Roof
|
|
const roofPanelWidth = Math.sqrt(Math.pow(naveWidth / 2, 2) + Math.pow(roofPeakHeight, 2));
|
|
const roofAngle = Math.atan2(roofPeakHeight, naveWidth / 2);
|
|
const roofGeo = new THREE.PlaneGeometry(roofPanelWidth, length); // Swapped width and length
|
|
const roofMat = wallMaterial.clone();
|
|
roofMat.map = wallTexture.clone();
|
|
roofMat.map.repeat.set(roofPanelWidth / 4, length / 4);
|
|
|
|
// Left and Right roof panels
|
|
createMesh(roofGeo, roofMat,
|
|
new THREE.Vector3(-naveWidth / 4, naveHeight + roofPeakHeight / 2, 0),
|
|
new THREE.Euler(Math.PI / 2, roofAngle, 0) // Flipped the roof right side up
|
|
);
|
|
createMesh(roofGeo, roofMat,
|
|
new THREE.Vector3(naveWidth / 4, naveHeight + roofPeakHeight / 2, 0),
|
|
new THREE.Euler(Math.PI / 2, -roofAngle, 0) // Flipped the roof right side up
|
|
);
|
|
|
|
// 7. Back gable wall (triangle part)
|
|
const gableShape = new THREE.Shape();
|
|
gableShape.moveTo(-naveWidth / 2, naveHeight);
|
|
gableShape.lineTo(naveWidth / 2, naveHeight);
|
|
gableShape.lineTo(0, naveHeight + roofPeakHeight);
|
|
const gableGeo = new THREE.ShapeGeometry(gableShape);
|
|
const gableMat = wallMaterial.clone();
|
|
gableMat.map = wallTexture.clone();
|
|
gableMat.map.repeat.set(naveWidth / 8, roofPeakHeight / 8);
|
|
createMesh(gableGeo, gableMat, new THREE.Vector3(0, 0, -length / 2));
|
|
|
|
// Note: crawlSurfaces and landingSurfaces might need to be updated if spiders/rats are used.
|
|
}
|
|
|
|
update(deltaTime) {
|
|
// Add any per-frame update logic here, if needed
|
|
}
|
|
}
|
|
new RoomWalls();
|