diff --git a/index.html b/index.html index 5beddf9..095f29a 100644 --- a/index.html +++ b/index.html @@ -10,63 +10,38 @@ window.onerror = function (msg, url, lineNo, columnNo, error) { const logDiv = document.getElementById('debug-log'); if (logDiv) { - const err = document.createElement('div'); - err.style.color = 'red'; - err.style.fontWeight = 'bold'; - err.style.background = 'white'; - err.style.padding = '5px'; - err.style.margin = '5px 0'; - err.textContent = `CRITICAL ERROR: ${msg} [Line: ${lineNo}]`; - logDiv.appendChild(err); - logDiv.scrollTop = logDiv.scrollHeight; + logDiv.style.display = 'block'; + logDiv.innerHTML += `
CRITICAL: ${msg} [Line: ${lineNo}]
`; } return false; }; - - function checkWebGL() { - try { - const canvas = document.createElement('canvas'); - const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); - if (gl && gl instanceof WebGLRenderingContext) return "WebGL Supported"; - else return "WebGL NOT Supported"; - } catch (e) { return "WebGL Error: " + e.message; } - } - function test2D() { - try { - const canvas = document.createElement('canvas'); - canvas.width = 100; - canvas.height = 100; - canvas.style.position = 'fixed'; - canvas.style.bottom = '10px'; - canvas.style.right = '10px'; - canvas.style.zIndex = '10001'; - canvas.style.border = '2px solid white'; - document.body.appendChild(canvas); - const ctx = canvas.getContext('2d'); - ctx.fillStyle = 'red'; - ctx.fillRect(0, 0, 100, 100); - window.log("2D Canvas Test: Rendered Red Square"); - } catch (e) { window.log("2D Canvas Error: " + e.message); } - } - window.addEventListener('load', test2D); + window.test2D = function () { + const c = document.createElement('canvas'); + c.width = 50; c.height = 50; + c.style.position = 'fixed'; c.bottom = '0'; c.right = '0'; c.zIndex = '10001'; + document.body.appendChild(c); + const ctx = c.getContext('2d'); + ctx.fillStyle = 'red'; ctx.fillRect(0, 0, 50, 50); + };
-
-

ECHOES

Click to Start

-

WASD to Move | Mouse to Look | E to Interact

+

WASD to Move | Mouse to Look | F Flashlight | P Debug

+
+
> Logger Initialized
+
diff --git a/src/Game.js b/src/Game.js index 3ffccc0..7574bcc 100644 --- a/src/Game.js +++ b/src/Game.js @@ -1,19 +1,12 @@ import { Graphics } from './Graphics.js'; import { World } from './World.js'; import { Player } from './Player.js'; -import * as THREE from 'three'; export class Game { constructor() { - window.log('Game constructor start'); - try { - this.graphics = new Graphics(); - this.world = new World(this.graphics.scene); - this.player = new Player(this.graphics.camera, this.world.colliders); - window.log('All components created successfully'); - } catch (e) { - window.log('CRITICAL ERROR during setup: ' + e.message); - } + this.graphics = new Graphics(); + this.world = new World(this.graphics.scene); + this.player = new Player(this.graphics.camera, this.world.colliders); this.isRunning = false; this.lastTime = 0; @@ -23,38 +16,21 @@ export class Game { setupUI() { const startScreen = document.getElementById('start-screen'); const hud = document.getElementById('hud'); - if (!startScreen) { - window.log('ERROR: start-screen not found'); - return; - } - startScreen.addEventListener('click', () => { - window.log('Start screen clicked'); - if (this.player) { - this.player.lockControls(); - } - startScreen.style.display = 'none'; - if (hud) hud.style.display = 'block'; - this.isRunning = true; - window.log('Game isRunning = true'); - }); + if (startScreen) { + startScreen.addEventListener('click', () => { + if (this.player) this.player.lockControls(); + startScreen.style.display = 'none'; + if (hud) hud.style.display = 'block'; + this.isRunning = true; + }); + } } start() { - window.log('Game.start() begin'); - try { - if (this.world) this.world.load(); - if (this.player) { - const playerObj = this.player.getObject(); - this.graphics.scene.add(playerObj); - } - window.log('World/Player loading complete'); - } catch (e) { - window.log('ERROR in Game.start(): ' + e.message); - } - + this.world.load(); + this.graphics.scene.add(this.player.getObject()); requestAnimationFrame(this.loop.bind(this)); - window.log('Animation loop requested'); } loop(time) { diff --git a/src/Graphics.js b/src/Graphics.js index 5ee9e86..e73cab5 100644 --- a/src/Graphics.js +++ b/src/Graphics.js @@ -4,44 +4,22 @@ export class Graphics { constructor() { // Main scene rendering this.scene = new THREE.Scene(); - this.scene.fog = new THREE.Fog(0x111122, 2, 15); - this.scene.background = new THREE.Color(0x111122); // Dark blue background instead of black + this.scene.fog = new THREE.Fog(0x000000, 2, 12); + this.scene.background = new THREE.Color(0x000000); this.camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 100); - // Real Screen Renderer - Force 400x300 for diagnostic visibility - const w = 400; - const h = 300; + // Real Screen Renderer this.renderer = new THREE.WebGLRenderer({ antialias: false }); - this.renderer.setSize(w, h); - this.renderer.setClearColor(0xff00ff); - this.renderer.domElement.style.position = 'fixed'; - this.renderer.domElement.style.top = '50%'; - this.renderer.domElement.style.left = '50%'; - this.renderer.domElement.style.transform = 'translate(-50%, -50%)'; - this.renderer.domElement.style.border = '5px solid yellow'; - this.renderer.domElement.style.zIndex = '1000'; + this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.domElement.id = 'three-canvas'; - document.body.appendChild(this.renderer.domElement); - window.log(`GL Vendor: ${this.renderer.getContext().getParameter(this.renderer.getContext().VENDOR)}`); - window.log(`Canvas forced to ${w}x${h} (centered)`); - - this.camera.position.set(5, 5, 5); - this.camera.lookAt(0, 0, 0); - - // Add a guaranteed object - const testCube = new THREE.Mesh( - new THREE.BoxGeometry(2, 2, 2), - new THREE.MeshBasicMaterial({ color: 0x00ff00 }) - ); - this.scene.add(testCube); - window.log('Green Cube added to scene'); + // Append to the correct container, not body directly + const container = document.getElementById('game-container'); + if (container) container.appendChild(this.renderer.domElement); + else document.body.appendChild(this.renderer.domElement); // --- Retro Pipeline Setup --- - - // 1. Off-screen Render Target (Small Resolution) - // We render the 3D scene here first. this.targetWidth = 320; this.targetHeight = 240; @@ -51,18 +29,15 @@ export class Graphics { format: THREE.RGBAFormat }); - // 2. Post-Processing Quad - // We render this quad to the screen, using the texture from the Render Target. this.postCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); this.postScene = new THREE.Scene(); const planeGeometry = new THREE.PlaneGeometry(2, 2); - // Custom Shader for Color Quantization const postMaterial = new THREE.ShaderMaterial({ uniforms: { tDiffuse: { value: this.renderTarget.texture }, - colorDepth: { value: 16.0 } // 16 levels per channel (4-bit per channel - 4096 colors) + colorDepth: { value: 24.0 } // 24 levels }, vertexShader: ` varying vec2 vUv; @@ -77,7 +52,6 @@ export class Graphics { varying vec2 vUv; void main() { vec4 tex = texture2D(tDiffuse, vUv); - // Quantize color and ensure it's not absolutely zeroed if there's light vec3 color = floor(tex.rgb * colorDepth + 0.5) / colorDepth; gl_FragColor = vec4(color, tex.a); } @@ -87,27 +61,17 @@ export class Graphics { this.postQuad = new THREE.Mesh(planeGeometry, postMaterial); this.postScene.add(this.postQuad); - // Input & Resize handling this.handleResize(); window.addEventListener('resize', this.handleResize.bind(this)); } - init() { - // Standard init placeholder - } + init() { } handleResize() { const aspect = window.innerWidth / window.innerHeight; - - // Update 3D Camera this.camera.aspect = aspect; this.camera.updateProjectionMatrix(); - - // Update Screen Renderer this.renderer.setSize(window.innerWidth, window.innerHeight); - - // Update Render Target Size (Fixed low height, aspect-correct width? Or Fixed Width?) - // Let's stick to fixed width 320 for that specific PSX feel, height auto. this.targetHeight = Math.floor(this.targetWidth / aspect); this.renderTarget.setSize(this.targetWidth, this.targetHeight); } @@ -115,19 +79,13 @@ export class Graphics { render() { if (!this.renderCount) this.renderCount = 0; this.renderCount++; + if (this.renderCount % 500 === 0) window.log(`Frame: ${this.renderCount}`); - if (this.renderCount % 500 === 0) { - window.log(`F:${this.renderCount} | Scene: ${this.scene.children.length} obj | Cam: ${this.camera.position.x.toFixed(1)},${this.camera.position.y.toFixed(1)},${this.camera.position.z.toFixed(1)}`); - } - - this.renderer.setClearColor(0xff00ff); - this.renderer.clear(); - - // 1. Render 3D Scene directly + // Diagnostic: Render 3D Scene directly to Screen + this.renderer.setRenderTarget(null); this.renderer.render(this.scene, this.camera); - /* - // Original Post-Processing Pipeline + /* // 1. Render 3D Scene to RenderTarget this.renderer.setRenderTarget(this.renderTarget); this.renderer.render(this.scene, this.camera); diff --git a/src/Player.js b/src/Player.js index aeb80a1..7d6be2b 100644 --- a/src/Player.js +++ b/src/Player.js @@ -71,7 +71,11 @@ export class Player { } toggleFlashlight() { - if (!this.controls || !this.controls.isLocked) return; // Only toggle when game is active + if (!this.controls) return; + // Note: isLocked might be false if user escaped, but we allow 'F' if controls exist? + // Better to allow F only when locked to avoid confusion. + if (!this.controls.isLocked) return; + this.flashlightOn = !this.flashlightOn; if (this.flashlight) { this.flashlight.visible = this.flashlightOn; @@ -79,48 +83,53 @@ export class Player { } lockControls() { - if (this.controls) this.controls.lock(); - else window.log('WARNING: Controls not initialized for locking'); + if (this.controls) { + this.controls.lock(); + window.log('Player.lockControls() called'); + } else { + window.log('WARNING: Controls not initialized for locking'); + } } getObject() { - return this.controls ? this.controls.getObject() : new THREE.Group(); + // PointerLockControls in this version operates directly on the camera + return this.camera; } update(dt) { - if (!this.controls || !this.controls.isLocked) return; + if (!this.controls) return; - // Friction-like dampening - // Simple direct velocity for now - this.velocity.x = 0; - this.velocity.z = 0; + // Debug logging for lock state (once per second roughly) + if (Math.random() < 0.01) { + // window.log(`Controls Locked: ${this.controls.isLocked}`); + } + + if (!this.controls.isLocked) return; + + // Friction-like dampening (simple decay) + this.velocity.x -= this.velocity.x * 10.0 * dt; + this.velocity.z -= this.velocity.z * 10.0 * dt; this.direction.z = Number(this.moveForward) - Number(this.moveBackward); this.direction.x = Number(this.moveRight) - Number(this.moveLeft); - this.direction.normalize(); // Ensure consistent speed in all directions + this.direction.normalize(); - if (this.moveForward || this.moveBackward) this.velocity.z -= this.direction.z * this.speed * dt; - if (this.moveLeft || this.moveRight) this.velocity.x -= this.direction.x * this.speed * dt; + if (this.moveForward || this.moveBackward) this.velocity.z -= this.direction.z * 100.0 * dt; + if (this.moveLeft || this.moveRight) this.velocity.x -= this.direction.x * 100.0 * dt; // Apply movement - this.controls.moveRight(-this.velocity.x); - this.controls.moveForward(-this.velocity.z); + this.controls.moveRight(-this.velocity.x * dt); + this.controls.moveForward(-this.velocity.z * dt); // Simple Collision: Push back - const playerPos = this.controls.getObject().position; - const playerRadius = 0.5; // approximated radius + const playerPos = this.camera.position; + const playerRadius = 0.5; for (const collider of this.colliders) { - // Assume colliders are BoxGeometry meshes aligned with axes for now const box = new THREE.Box3().setFromObject(collider); - - // Check if player is inside the box (expanded by radius) - // We only check X/Z for walls if (playerPos.x > box.min.x - playerRadius && playerPos.x < box.max.x + playerRadius && playerPos.z > box.min.z - playerRadius && playerPos.z < box.max.z + playerRadius) { - // Very simple resolution: determine closest edge and push out - // This is a naive implementation but works for static orthogonal walls const dx1 = Math.abs(playerPos.x - (box.min.x - playerRadius)); const dx2 = Math.abs(playerPos.x - (box.max.x + playerRadius)); const dz1 = Math.abs(playerPos.z - (box.min.z - playerRadius)); diff --git a/src/World.js b/src/World.js index a54ca66..b868341 100644 --- a/src/World.js +++ b/src/World.js @@ -7,45 +7,59 @@ export class World { } load() { - window.log('World.load() start'); - // Grid helper for depth - this.scene.add(new THREE.GridHelper(20, 20)); + // Standard lighting for horror + const ambientLight = new THREE.AmbientLight(0x404040, 1.0); // Full brightness ambient for testing + this.scene.add(ambientLight); - // Floor (Basic Material - no light needed) - const floorGeo = new THREE.PlaneGeometry(20, 20); - const floorMat = new THREE.MeshBasicMaterial({ - color: 0x333333, - side: THREE.DoubleSide + // Floor + const floorGeo = new THREE.PlaneGeometry(30, 30); + const floorMat = new THREE.MeshStandardMaterial({ + color: 0x222222, + roughness: 0.9 }); const floor = new THREE.Mesh(floorGeo, floorMat); floor.rotation.x = -Math.PI / 2; this.scene.add(floor); // Simple walls - this.createWall(0, 2.5, -10, 20, 5); // Back - this.createWall(0, 2.5, 10, 20, 5); // Front - this.createWall(-10, 2.5, 0, 20, 5, true); // Left - this.createWall(10, 2.5, 0, 20, 5, true); // Right + 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 - // Add a reference cube (Bright Yellow Basic Material) - const cube = new THREE.Mesh( + // 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; + this.createPillar(px, 2.5, pz); + } + + // Add a red object to find + const target = new THREE.Mesh( new THREE.BoxGeometry(1, 1, 1), - new THREE.MeshBasicMaterial({ color: 0xffff00 }) + new THREE.MeshStandardMaterial({ color: 0x880000 }) ); - cube.position.set(0, 0.5, -5); - this.scene.add(cube); - this.colliders.push(cube); + target.position.set(5, 0.5, -5); + this.scene.add(target); + this.colliders.push(target); } createWall(x, y, z, width, height, rotate = false) { - window.log(`Creating wall at ${x},${z}`); const geo = new THREE.BoxGeometry(width, height, 0.5); - const mat = new THREE.MeshBasicMaterial({ color: 0x555555 }); + 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); + } } diff --git a/src/main.js b/src/main.js index 9063886..183eff5 100644 --- a/src/main.js +++ b/src/main.js @@ -1,3 +1,5 @@ +import { Game } from './Game.js'; + window.log = (msg) => { const logDiv = document.getElementById('debug-log'); if (logDiv) { @@ -9,6 +11,14 @@ window.log = (msg) => { console.log(msg); }; +if (window.test2D) window.test2D(); +window.log(`Searching for WebGL...`); +try { + const canvas = document.createElement('canvas'); + const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); + window.log(gl ? "WebGL Found" : "WebGL NOT Found"); +} catch (e) { window.log("WebGL Check Error: " + e.message); } + // Toggle debug log with 'P' window.addEventListener('keydown', (e) => { if (e.code === 'KeyP') { @@ -19,15 +29,7 @@ window.addEventListener('keydown', (e) => { } }); -import * as THREE from 'three'; -window.log(`THREE Revision: ${THREE.REVISION}`); -if (window.checkWebGL) window.log(`System Check: ${window.checkWebGL()}`); - -import { Game } from './Game.js'; - window.addEventListener('DOMContentLoaded', () => { - window.log('DOM Content Loaded'); const game = new Game(); game.start(); - window.log('Game Started'); });