From 94b6d7ac80238e8a301ed1321d875fba4efeb7a2 Mon Sep 17 00:00:00 2001 From: eliazarw Date: Sat, 3 Jan 2026 09:21:52 +0000 Subject: [PATCH] feat: Implement procedural textures and enhanced furniture generation with collision avoidance. --- src/Player.js | 16 +- src/World.js | 456 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 432 insertions(+), 40 deletions(-) diff --git a/src/Player.js b/src/Player.js index 0591378..9c380fb 100644 --- a/src/Player.js +++ b/src/Player.js @@ -87,19 +87,21 @@ export class Player { // 2. Lights // Main SpotLight (The beam) - this.flashlight = new THREE.SpotLight(0xffffff, 10); + this.flashlight = new THREE.SpotLight(0xffffff, 3.0); // Reduced brightness this.flashlight.angle = Math.PI / 6; - this.flashlight.penumbra = 0.3; - this.flashlight.decay = 1.5; - this.flashlight.distance = 60; + this.flashlight.penumbra = 0.5; // Softer edges + this.flashlight.decay = 2.0; // Faster falloff + this.flashlight.distance = 50; this.flashlight.position.set(0, 0, -0.1); // At tip - this.flashlight.target.position.set(0, 0, -10); // Aim forward + // Aim inward to crosshair (Converge) + // Group is at (0.3, -0.25), so target needs to be (-0.3, 0.25) to hit center 0,0 relative to camera + this.flashlight.target.position.set(-0.3, 0.25, -20); this.flashlightGroup.add(this.flashlight); this.flashlightGroup.add(this.flashlight.target); // PointLight (The glow around the player) - this.bulbLight = new THREE.PointLight(0xffffff, 2, 4); // Low range (4m) + this.bulbLight = new THREE.PointLight(0xffffff, 0.5, 3); // Very dim local glow this.bulbLight.position.set(0, 0, -0.15); // Slightly ahead of tip this.flashlightGroup.add(this.bulbLight); } @@ -271,7 +273,7 @@ export class Player { this.flashlight.angle = Math.max(0.1, this.flashlight.angle - angleSpeed); } if (this.adjustBright) { - this.flashlight.intensity = Math.min(50, this.flashlight.intensity + speed * 10); + this.flashlight.intensity = Math.min(15, this.flashlight.intensity + speed * 10); this.flashlight.angle = Math.min(Math.PI / 2, this.flashlight.angle + angleSpeed); } // Sync bulb light diff --git a/src/World.js b/src/World.js index a4387cd..2479e85 100644 --- a/src/World.js +++ b/src/World.js @@ -4,34 +4,54 @@ export class World { constructor(scene) { this.scene = scene; this.colliders = []; + this.staticObstacles = []; // Track pillars etc for spawning this.dustParticles = null; } load() { + // Generate Textures + this.texConcrete = this.createProceduralTexture('concrete'); + this.texWall = this.createProceduralTexture('wall'); + this.texWood = this.createProceduralTexture('wood'); + this.texFabric = this.createProceduralTexture('fabric'); + // Standard lighting for horror const ambientLight = new THREE.AmbientLight(0x404040, 0.2); // Very dim ambient this.scene.add(ambientLight); - // Floor - const floorGeo = new THREE.PlaneGeometry(30, 30); + // Floor (Dirty Concrete) + const floorGeo = new THREE.PlaneGeometry(60, 60); const floorMat = new THREE.MeshStandardMaterial({ - color: 0x222222, - roughness: 0.9 + map: this.texConcrete, + roughness: 0.9, + metalness: 0.1 }); const floor = new THREE.Mesh(floorGeo, floorMat); floor.rotation.x = -Math.PI / 2; this.scene.add(floor); - // Simple walls - this.createWall(0, 2.5, -15, 30, 5); // Back - this.createWall(0, 2.5, 15, 30, 5); // Front - this.createWall(-15, 2.5, 0, 30, 5, true); // Left - this.createWall(15, 2.5, 0, 30, 5, true); // Right + // Ceiling (Dirty Concrete, Darker) + const ceilingGeo = new THREE.PlaneGeometry(60, 60); + const ceilingMat = new THREE.MeshStandardMaterial({ + map: this.texConcrete, + roughness: 1.0, + metalness: 0 + }); + const ceiling = new THREE.Mesh(ceilingGeo, ceilingMat); + ceiling.rotation.x = Math.PI / 2; + ceiling.position.y = 5; // Top of walls + this.scene.add(ceiling); - // Add some "horror" pillars - for (let i = 0; i < 8; i++) { - const px = (Math.random() - 0.5) * 20; - const pz = (Math.random() - 0.5) * 20; + // Simple walls (Expanded to 60x60 with Moldy Plaster) + this.createWall(0, 2.5, -30, 60, 5); // Back + this.createWall(0, 2.5, 30, 60, 5); // Front + this.createWall(-30, 2.5, 0, 60, 5, true); // Left + this.createWall(30, 2.5, 0, 60, 5, true); // Right + + // Add some "horror" pillars (Spread out, Concrete) + for (let i = 0; i < 12; i++) { + const px = (Math.random() - 0.5) * 50; + const pz = (Math.random() - 0.5) * 50; this.createPillar(px, 2.5, pz); } @@ -44,9 +64,397 @@ export class World { this.scene.add(target); this.colliders.push(target); + this.createFurniture(45); this.createDust(); } + createProceduralTexture(type) { + const size = 512; + const canvas = document.createElement('canvas'); + canvas.width = size; + canvas.height = size; + const ctx = canvas.getContext('2d'); + + // Base fill + if (type === 'concrete') { + ctx.fillStyle = '#333333'; + ctx.fillRect(0, 0, size, size); + // Noise & Stains + for (let i = 0; i < 2000; i++) { + ctx.fillStyle = Math.random() > 0.5 ? '#222222' : '#444444'; + ctx.globalAlpha = 0.1; + const x = Math.random() * size; + const y = Math.random() * size; + const r = Math.random() * 50; + ctx.beginPath(); + ctx.arc(x, y, r, 0, Math.PI * 2); + ctx.fill(); + } + } else if (type === 'wall') { + ctx.fillStyle = '#555555'; // Plaster + ctx.fillRect(0, 0, size, size); + // General Grime + for (let i = 0; i < 1000; i++) { + ctx.fillStyle = '#333333'; + ctx.globalAlpha = 0.05; + ctx.fillRect(Math.random() * size, Math.random() * size, Math.random() * 100, Math.random() * 100); + } + // Mold at bottom + const grad = ctx.createLinearGradient(0, size, 0, size * 0.5); + grad.addColorStop(0, 'rgba(10, 30, 10, 0.8)'); // Black-Green + grad.addColorStop(1, 'rgba(10, 30, 10, 0)'); + ctx.fillStyle = grad; + ctx.globalAlpha = 1.0; + ctx.fillRect(0, 0, size, size); + } else if (type === 'wood') { + ctx.fillStyle = '#3e2723'; + ctx.fillRect(0, 0, size, size); + // Wood grain streaks + for (let i = 0; i < 500; i++) { + ctx.fillStyle = '#281815'; + ctx.globalAlpha = 0.3; + const x = Math.random() * size; + const w = Math.random() * 10 + 2; + ctx.fillRect(x, 0, w, size); + } + } else if (type === 'fabric') { + ctx.fillStyle = '#4e342e'; // Faded brown + ctx.fillRect(0, 0, size, size); + // Crosshatch noise + ctx.strokeStyle = '#3e2723'; + ctx.globalAlpha = 0.2; + for (let i = 0; i < 200; i++) { + ctx.beginPath(); + ctx.moveTo(0, Math.random() * size); + ctx.lineTo(size, Math.random() * size); + ctx.stroke(); + } + } + + const tex = new THREE.CanvasTexture(canvas); + tex.wrapS = THREE.RepeatWrapping; + tex.wrapT = THREE.RepeatWrapping; + return tex; + } + + createWall(x, y, z, width, height, rotate = false) { + const geo = new THREE.BoxGeometry(width, height, 0.5); + const mat = new THREE.MeshStandardMaterial({ + map: this.texWall, + roughness: 0.95 + }); + // Tile the texture + mat.map.repeat.set(width / 5, height / 5); + + const wall = new THREE.Mesh(geo, mat); + wall.position.set(x, y, z); + if (rotate) wall.rotation.y = Math.PI / 2; + this.scene.add(wall); + this.colliders.push(wall); + } + + createPillar(x, y, z) { + const geo = new THREE.BoxGeometry(1, 5, 1); + const mat = new THREE.MeshStandardMaterial({ + map: this.texConcrete, // Reuse concrete for pillars + roughness: 0.9 + }); + const pillar = new THREE.Mesh(geo, mat); + pillar.position.set(x, y, z); + this.scene.add(pillar); + this.colliders.push(pillar); + this.staticObstacles.push(pillar); // Add to spawn blocker list + } + + createFurniture(count) { + const props = []; + + for (let i = 0; i < count; i++) { + // Try 10 times to find a valid spot + let px, pz, valid = false; + for (let attempt = 0; attempt < 10; attempt++) { + px = (Math.random() - 0.5) * 54; // Spread almost to walls (60 width) + pz = (Math.random() - 0.5) * 54; + + // Avoid center spawn + if (Math.abs(px) < 6 && Math.abs(pz) < 6) continue; + + // Check distance to other props + let overlap = false; + for (const p of props) { + const dx = p.px - px; + const dz = p.pz - pz; + if (dx * dx + dz * dz < 16) { // Min distance 4 units + overlap = true; + break; + } + } + + // ALSO Check distance to Pillars (Static Obstacles) + if (!overlap) { + for (const obs of this.staticObstacles) { + const dx = obs.position.x - px; + const dz = obs.position.z - pz; + if (dx * dx + dz * dz < 9) { // 3m distance from pillars + overlap = true; + break; + } + } + } + + if (!overlap) { + valid = true; + props.push({ px, pz }); + break; + } + } + + if (!valid) continue; // Skip if no spot found + + const type = Math.floor(Math.random() * 10); // Increased variety to 10 types + const rot = Math.random() * Math.PI * 2; + + const group = new THREE.Group(); + group.position.set(px, 0, pz); + group.rotation.y = rot; + this.scene.add(group); + + if (type === 0) this.spawnCouch(group); + else if (type === 1) this.spawnTable(group); + else if (type === 2) this.spawnChair(group); + else if (type === 3) this.spawnLamp(group); + else if (type === 4) this.spawnClock(group); + else if (type === 5) this.spawnMannequin(group); + else if (type === 6) this.spawnTV(group); + else if (type === 7) this.spawnBed(group); // New + else if (type === 8) this.spawnBookshelf(group); // New + else if (type === 9) this.spawnDrawer(group); // New + } + } + + spawnBed(group) { + this.addColliderBox(group, 1.2, 0.6, 2.0); + + const frameMat = new THREE.MeshStandardMaterial({ color: 0x3e2723, roughness: 0.9, metalness: 0.4 }); + const mattressMat = new THREE.MeshStandardMaterial({ map: this.texFabric, color: 0x888877, roughness: 1.0 }); + + const f1 = new THREE.Mesh(new THREE.BoxGeometry(1.2, 0.1, 2.0), frameMat); f1.position.y = 0.3; group.add(f1); + const hbTop = new THREE.Mesh(new THREE.BoxGeometry(1.2, 0.05, 0.05), frameMat); hbTop.position.set(0, 0.9, -1.0); group.add(hbTop); + const legBL = new THREE.Mesh(new THREE.BoxGeometry(0.1, 1.0, 0.1), frameMat); legBL.position.set(-0.55, 0.5, -1.0); group.add(legBL); + const legBR = new THREE.Mesh(new THREE.BoxGeometry(0.1, 1.0, 0.1), frameMat); legBR.position.set(0.55, 0.5, -1.0); group.add(legBR); + + const matMesh = new THREE.Mesh(new THREE.BoxGeometry(1.1, 0.25, 1.9), mattressMat); matMesh.position.y = 0.45; matMesh.rotation.z = (Math.random() - 0.5) * 0.05; group.add(matMesh); + } + + spawnBookshelf(group) { + this.addColliderBox(group, 1.1, 2.0, 0.5); + + const mat = new THREE.MeshStandardMaterial({ map: this.texWood, color: 0x4a3c31, roughness: 0.9 }); + + const left = new THREE.Mesh(new THREE.BoxGeometry(0.1, 2.0, 0.4), mat); left.position.set(-0.5, 1.0, 0); group.add(left); + const right = new THREE.Mesh(new THREE.BoxGeometry(0.1, 2.0, 0.4), mat); right.position.set(0.5, 1.0, 0); group.add(right); + const top = new THREE.Mesh(new THREE.BoxGeometry(1.1, 0.1, 0.4), mat); top.position.set(0, 2.0, 0); group.add(top); + + for (let y = 0.5; y < 2.0; y += 0.5) { + if (Math.random() < 0.2) continue; + const shelf = new THREE.Mesh(new THREE.BoxGeometry(1.0, 0.05, 0.38), mat); shelf.position.set(0, y, 0); shelf.rotation.z = (Math.random() - 0.5) * 0.2; group.add(shelf); + if (Math.random() > 0.5) { + const book = new THREE.Mesh(new THREE.BoxGeometry(0.1, 0.25, 0.2), new THREE.MeshStandardMaterial({ color: Math.random() * 0xffffff })); + book.position.set((Math.random() - 0.5) * 0.8, y + 0.15, 0); book.rotation.z = (Math.random() - 0.5) * 0.5; group.add(book); + } + } + } + + spawnDrawer(group) { + this.addColliderBox(group, 0.9, 1.2, 0.5); + + const mat = new THREE.MeshStandardMaterial({ map: this.texWood, color: 0x3d2b1f, roughness: 0.8 }); + + const body = new THREE.Mesh(new THREE.BoxGeometry(0.9, 1.2, 0.5), mat); body.position.y = 0.6; group.add(body); + + [0.3, 0.6, 0.9].forEach(y => { + if (Math.random() < 0.2) return; + const d = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.25, 0.05), mat); + const offset = Math.random() < 0.3 ? 0.2 : 0; + d.position.set(0, y, 0.26 + offset); + group.add(d); + }); + } + addColliderBox(group, w, h, d) { + // Create invisible hitbox: slightly smaller than visual to forgive AABB rotation errors + const geo = new THREE.BoxGeometry(w * 0.85, h, d * 0.85); + const mat = new THREE.MeshBasicMaterial({ visible: false }); // Invisible + const box = new THREE.Mesh(geo, mat); + box.position.y = h / 2; + group.add(box); + this.colliders.push(box); + } + + spawnCouch(group) { + this.addColliderBox(group, 2.2, 1.0, 0.8); + + // Use worn fabric texture + const mat = new THREE.MeshStandardMaterial({ + map: this.texFabric, + roughness: 1.0, + color: 0x666666 + }); + + // Base (Sagging) + const base = new THREE.Mesh(new THREE.BoxGeometry(2.2, 0.45, 0.8), mat); + base.position.y = 0.225; + group.add(base); + + // Back (Uneven) + const back = new THREE.Mesh(new THREE.BoxGeometry(2.2, 0.65, 0.2), mat); + back.position.set(0, 0.7, -0.3); + back.rotation.x = -0.1; + group.add(back); + + // Arms (Worn) + const armL = new THREE.Mesh(new THREE.BoxGeometry(0.3, 0.45, 0.85), mat); + armL.position.set(-1.0, 0.5, 0); + group.add(armL); + + const armR = new THREE.Mesh(new THREE.BoxGeometry(0.3, 0.45, 0.85), mat); + armR.position.set(1.0, 0.5, 0); + group.add(armR); + + // Cushions + const cushionL = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.1, 0.6), mat); + cushionL.position.set(-0.5, 0.5, 0.1); + cushionL.rotation.y = 0.1; cushionL.rotation.z = 0.05; + group.add(cushionL); + + const cushionR = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.1, 0.6), mat); + cushionR.position.set(0.5, 0.5, 0.1); + cushionR.rotation.y = -0.05; + group.add(cushionR); + } + + spawnTable(group) { + this.addColliderBox(group, 1.5, 0.9, 1.0); + + const mat = new THREE.MeshStandardMaterial({ map: this.texWood, roughness: 0.8, metalness: 0.1 }); + + // Top + const top = new THREE.Mesh(new THREE.BoxGeometry(1.5, 0.1, 1.0), mat); + top.position.y = 0.8; + group.add(top); + + // Legs + const legGeo = new THREE.BoxGeometry(0.1, 0.8, 0.1); + const positions = [[-0.6, -0.4], [0.6, -0.4], [-0.6, 0.4], [0.6, 0.4]]; + + positions.forEach((pos) => { + const leg = new THREE.Mesh(legGeo, mat); + leg.position.set(pos[0], 0.4, pos[1]); + leg.rotation.z = (Math.random() - 0.5) * 0.1; + leg.rotation.x = (Math.random() - 0.5) * 0.1; + group.add(leg); + }); + } + + spawnChair(group) { + this.addColliderBox(group, 0.5, 0.8, 0.5); // Simple box for chair + + const mat = new THREE.MeshStandardMaterial({ map: this.texWood, roughness: 0.9 }); + + // Seat + const seat = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.08, 0.5), mat); + seat.position.y = 0.5; + seat.rotation.z = 0.02; + group.add(seat); + + // Back + const railL = new THREE.Mesh(new THREE.BoxGeometry(0.05, 0.5, 0.05), mat); railL.position.set(-0.2, 0.75, -0.22); group.add(railL); + const railR = new THREE.Mesh(new THREE.BoxGeometry(0.05, 0.5, 0.05), mat); railR.position.set(0.2, 0.75, -0.22); group.add(railR); + const topRail = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.1, 0.05), mat); topRail.position.set(0, 1.0, -0.22); group.add(topRail); + + // Legs + const legGeo = new THREE.BoxGeometry(0.05, 0.5, 0.05); + [[-0.2, -0.2], [0.2, -0.2], [-0.2, 0.2], [0.2, 0.2]].forEach(pos => { + const leg = new THREE.Mesh(legGeo, mat); + leg.position.set(pos[0], 0.25, pos[1]); + group.add(leg); + }); + + if (Math.random() < 0.1) { + group.rotation.x = Math.PI / 2; + group.position.y = 0.2; + } + } + + spawnLamp(group) { + this.addColliderBox(group, 0.1, 2.0, 0.1); + + const mat = new THREE.MeshStandardMaterial({ color: 0x3e2723, roughness: 0.9, metalness: 0.3 }); + const pole = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.05, 2.0, 8), mat); + pole.position.y = 1.0; pole.rotation.z = 0.1; + group.add(pole); // No collider + + const shade = new THREE.Mesh(new THREE.ConeGeometry(0.4, 0.5, 16, 1, true), new THREE.MeshStandardMaterial({ color: 0xd7ccc8, side: THREE.DoubleSide, roughness: 1.0 })); + shade.position.set(-0.1, 1.9, 0); shade.rotation.z = 0.3; + group.add(shade); + } + + spawnClock(group) { + this.addColliderBox(group, 0.7, 2.2, 0.6); + + const woodColor = 0x2a1a10; + const mat = new THREE.MeshStandardMaterial({ color: woodColor, roughness: 0.6 }); + const base = new THREE.Mesh(new THREE.BoxGeometry(0.7, 0.4, 0.6), mat); base.position.y = 0.2; group.add(base); + const body = new THREE.Mesh(new THREE.BoxGeometry(0.5, 1.4, 0.45), mat); body.position.y = 1.1; group.add(body); + const headBox = new THREE.Mesh(new THREE.BoxGeometry(0.7, 0.7, 0.5), mat); headBox.position.y = 2.15; group.add(headBox); + const top = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.35, 0.2, 4), mat); top.rotation.y = Math.PI / 4; top.position.y = 2.6; group.add(top); + const face = new THREE.Mesh(new THREE.CircleGeometry(0.25, 32), new THREE.MeshBasicMaterial({ color: 0xeeddcc })); face.position.set(0, 2.15, 0.26); group.add(face); + const glass = new THREE.Mesh(new THREE.PlaneGeometry(0.3, 1.0), new THREE.MeshStandardMaterial({ color: 0x111111, roughness: 0.1, metalness: 0.8 })); glass.position.set(0, 1.1, 0.23); group.add(glass); + const pendulum = new THREE.Mesh(new THREE.CylinderGeometry(0.1, 0.1, 0.05, 16), new THREE.MeshStandardMaterial({ color: 0xae8b0c, metalness: 0.8, roughness: 0.3 })); pendulum.rotation.x = Math.PI / 2; pendulum.position.set(0, 0.9, 0.24); group.add(pendulum); + const rod = new THREE.Mesh(new THREE.BoxGeometry(0.02, 0.8, 0.02), new THREE.MeshStandardMaterial({ color: 0xae8b0c })); rod.position.set(0, 1.3, 0.24); group.add(rod); + } + + spawnMannequin(group) { + this.addColliderBox(group, 0.5, 1.9, 0.4); + + const mat = new THREE.MeshStandardMaterial({ color: 0xd0c0b0, roughness: 0.4 }); + const hips = new THREE.Mesh(new THREE.BoxGeometry(0.35, 0.2, 0.25), mat); hips.position.y = 0.95; group.add(hips); + const legGeo = new THREE.CylinderGeometry(0.09, 0.07, 0.95, 8); + const legL = new THREE.Mesh(legGeo, mat); legL.position.set(-0.12, 0.475, 0); group.add(legL); + const legR = new THREE.Mesh(legGeo, mat); legR.position.set(0.12, 0.475, 0); group.add(legR); + const torso = new THREE.Mesh(new THREE.BoxGeometry(0.38, 0.6, 0.24), mat); torso.position.y = 1.35; group.add(torso); + const chest = new THREE.Mesh(new THREE.BoxGeometry(0.45, 0.2, 0.26), mat); chest.position.y = 1.6; group.add(chest); + const armGeo = new THREE.CylinderGeometry(0.06, 0.05, 0.7, 8); + const armL = new THREE.Mesh(armGeo, mat); armL.position.set(-0.28, 1.35, 0); armL.rotation.z = 0.1; group.add(armL); + const armR = new THREE.Mesh(armGeo, mat); armR.position.set(0.28, 1.35, 0); armR.rotation.z = -0.1; group.add(armR); + const neck = new THREE.Mesh(new THREE.CylinderGeometry(0.06, 0.07, 0.15), mat); neck.position.y = 1.75; group.add(neck); + const head = new THREE.Mesh(new THREE.SphereGeometry(0.12, 16, 16), mat); head.position.y = 1.88; group.add(head); + } + + spawnTV(group) { + this.addColliderBox(group, 0.8, 1.5, 0.6); + + const standMat = new THREE.MeshStandardMaterial({ color: 0x4a3c31, roughness: 0.9 }); + const stand = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.6, 0.5), standMat); stand.position.y = 0.3; group.add(stand); + + const tvMat = new THREE.MeshStandardMaterial({ color: 0x1a1a1a, roughness: 0.5 }); + const tv = new THREE.Mesh(new THREE.BoxGeometry(0.7, 0.55, 0.55), tvMat); tv.position.y = 0.875; group.add(tv); + + const screenMat = new THREE.MeshStandardMaterial({ color: 0x111111, metalness: 0.6, roughness: 0.2 }); + const screen = new THREE.Mesh(new THREE.SphereGeometry(0.35, 32, 32, 0, Math.PI * 2, 0, 0.6), screenMat); + screen.position.set(0, 0.9, 0.15); screen.scale.set(0.9, 0.7, 0.5); screen.rotation.x = -Math.PI / 2; group.add(screen); + + const sidePanel = new THREE.Mesh(new THREE.BoxGeometry(0.15, 0.4, 0.05), new THREE.MeshStandardMaterial({ color: 0x333333 })); + sidePanel.position.set(0.25, 0.875, 0.28); group.add(sidePanel); + const knob1 = new THREE.Mesh(new THREE.CylinderGeometry(0.03, 0.03, 0.05), new THREE.MeshStandardMaterial({ color: 0x888888 })); + knob1.rotation.x = Math.PI / 2; knob1.position.set(0.25, 0.95, 0.31); group.add(knob1); + const knob2 = knob1.clone(); knob2.position.set(0.25, 0.8, 0.31); group.add(knob2); + + const ant = new THREE.Mesh(new THREE.CylinderGeometry(0.005, 0.005, 0.6), new THREE.MeshStandardMaterial({ color: 0xaaaaaa })); + ant.position.set(-0.1, 1.3, 0); ant.rotation.z = 0.4; group.add(ant); + const ant2 = ant.clone(); ant2.position.set(0.1, 1.3, 0); ant2.rotation.z = -0.4; group.add(ant2); + } + + createDust() { // Create 800 dust particles (Reduced) const count = 800; @@ -56,9 +464,9 @@ export class World { const velocities = []; for (let i = 0; i < count; i++) { - positions[i * 3] = (Math.random() - 0.5) * 40; + positions[i * 3] = (Math.random() - 0.5) * 60; positions[i * 3 + 1] = Math.random() * 5; - positions[i * 3 + 2] = (Math.random() - 0.5) * 40; + positions[i * 3 + 2] = (Math.random() - 0.5) * 60; colors[i * 3] = 0; // Start invisible (black) colors[i * 3 + 1] = 0; @@ -88,24 +496,6 @@ export class World { this.scene.add(this.dustParticles); } - createWall(x, y, z, width, height, rotate = false) { - const geo = new THREE.BoxGeometry(width, height, 0.5); - const mat = new THREE.MeshStandardMaterial({ color: 0x333333 }); - const wall = new THREE.Mesh(geo, mat); - wall.position.set(x, y, z); - if (rotate) wall.rotation.y = Math.PI / 2; - this.scene.add(wall); - this.colliders.push(wall); - } - - createPillar(x, y, z) { - const geo = new THREE.BoxGeometry(1, 5, 1); - const mat = new THREE.MeshStandardMaterial({ color: 0x444444 }); - const pillar = new THREE.Mesh(geo, mat); - pillar.position.set(x, y, z); - this.scene.add(pillar); - this.colliders.push(pillar); - } update(dt, player) { if (!this.dustParticles) return;