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
+
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');
});