feat: Introduce robust diagnostic setup with fixed-size renderer, enhanced logging, system checks, and improved error handling for initial game components.

This commit is contained in:
2026-01-03 07:16:53 +00:00
parent ad5b025a8b
commit 31a4a5ee9b
7 changed files with 155 additions and 44 deletions

View File

@@ -1,14 +1,62 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Horror Game</title>
<link rel="stylesheet" href="style.css">
<script>
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;
}
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);
</script>
</head>
<body>
<div id="game-container"></div>
<div id="debug-log" style="position: absolute; top: 10px; left: 10px; z-index: 999; color: lime; font-family: monospace; pointer-events: none; background: rgba(0,0,0,0.5);"></div>
<div id="debug-log"
style="position: absolute; top: 10px; left: 10px; z-index: 10000; color: lime; font-family: monospace; pointer-events: none; background: rgba(0,0,0,0.8); max-height: 80%; overflow-y: auto; font-size: 14px; padding: 10px; width: 300px;">
</div>
<div id="ui-layer">
<div id="start-screen">
@@ -23,4 +71,5 @@
<script type="module" src="/src/main.js"></script>
</body>
</html>

View File

@@ -1,52 +1,71 @@
import { Graphics } from './Graphics.js';
import { World } from './World.js';
import { Player } from './Player.js';
import * as THREE from 'three';
export class Game {
constructor() {
this.graphics = new Graphics();
this.world = new World(this.graphics.scene);
this.player = new Player(this.graphics.camera, this.world.colliders);
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.isRunning = false;
this.lastTime = 0;
this.setupUI();
}
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', () => {
this.player.lockControls();
window.log('Start screen clicked');
if (this.player) {
this.player.lockControls();
}
startScreen.style.display = 'none';
hud.style.display = 'block';
if (hud) hud.style.display = 'block';
this.isRunning = true;
window.log('Game isRunning = true');
});
}
start() {
this.graphics.init();
this.world.load();
// Add player to scene if needed, but usually player moves camera
this.graphics.scene.add(this.player.getObject());
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);
}
requestAnimationFrame(this.loop.bind(this));
window.log('Animation loop requested');
}
loop(time) {
requestAnimationFrame(this.loop.bind(this));
const dt = this.lastTime === 0 ? 0 : Math.min((time - this.lastTime) / 1000, 0.1); // Cap dt
const dt = this.lastTime === 0 ? 0 : Math.min((time - this.lastTime) / 1000, 0.1);
this.lastTime = time;
if (this.isRunning) {
this.player.update(dt);
// this.world.update(dt);
}
this.graphics.render();
requestAnimationFrame(this.loop.bind(this));
}
}

View File

@@ -9,26 +9,35 @@ export class Graphics {
this.camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 100);
// Real Screen Renderer
// Real Screen Renderer - Force 400x300 for diagnostic visibility
const w = 400;
const h = 300;
this.renderer = new THREE.WebGLRenderer({ antialias: false });
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.setClearColor(0xff00ff); // STRIKING MAGENTA for diagnostic
this.renderer.domElement.style.border = '5px solid yellow'; // VISIBLE BORDER
this.renderer.domElement.style.zIndex = '100'; // FORCE TO FRONT
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.domElement.id = 'three-canvas';
const container = document.getElementById('game-container');
if (container) {
container.appendChild(this.renderer.domElement);
window.log('Renderer attached to DOM');
} else {
window.log('ERROR: game-container not found');
}
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.scene.add(new THREE.AxesHelper(10)); // Add axis lines (Red, Green, Blue)
this.camera.position.set(5, 5, 5); // Move camera out of the floor
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');
// --- Retro Pipeline Setup ---
// 1. Off-screen Render Target (Small Resolution)
@@ -106,11 +115,15 @@ export class Graphics {
render() {
if (!this.renderCount) this.renderCount = 0;
this.renderCount++;
if (this.renderCount % 100 === 0) window.log(`Rendering frame ${this.renderCount}`);
// --- Diagnostic: Render directly to screen ---
// 1. Render 3D Scene to Screen
this.renderer.setRenderTarget(null);
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
this.renderer.render(this.scene, this.camera);
/*

View File

@@ -1,5 +1,7 @@
import * as THREE from 'three';
import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls.js';
// Note: In some environments this might need to be 'three/addons/controls/PointerLockControls.js'
// but we'll stick to this for now as it's standard examples path.
export class Player {
constructor(camera, colliders) {
@@ -11,7 +13,12 @@ export class Player {
this.height = 1.7; // Eyes height
// Init controls
this.controls = new PointerLockControls(camera, document.body);
try {
this.controls = new PointerLockControls(camera, document.body);
window.log('PointerLockControls initialized');
} catch (e) {
window.log(`ERROR initializing controls: ${e.message}`);
}
// Movement state
this.moveForward = false;
@@ -64,7 +71,7 @@ export class Player {
}
toggleFlashlight() {
if (!this.controls.isLocked) return; // Only toggle when game is active
if (!this.controls || !this.controls.isLocked) return; // Only toggle when game is active
this.flashlightOn = !this.flashlightOn;
if (this.flashlight) {
this.flashlight.visible = this.flashlightOn;
@@ -72,15 +79,16 @@ export class Player {
}
lockControls() {
this.controls.lock();
if (this.controls) this.controls.lock();
else window.log('WARNING: Controls not initialized for locking');
}
getObject() {
return this.controls.getObject();
return this.controls ? this.controls.getObject() : new THREE.Group();
}
update(dt) {
if (!this.controls.isLocked) return;
if (!this.controls || !this.controls.isLocked) return;
// Friction-like dampening
// Simple direct velocity for now

View File

@@ -7,6 +7,7 @@ export class World {
}
load() {
window.log('World.load() start');
// Grid helper for depth
this.scene.add(new THREE.GridHelper(20, 20));
@@ -37,6 +38,7 @@ export class World {
}
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 wall = new THREE.Mesh(geo, mat);

View File

@@ -1,9 +1,28 @@
window.log = (msg) => {
const logDiv = document.getElementById('debug-log');
if (logDiv) logDiv.innerHTML += `> ${msg}<br>`;
if (logDiv) {
const span = document.createElement('div');
span.textContent = `> ${msg}`;
logDiv.appendChild(span);
logDiv.scrollTop = logDiv.scrollHeight;
}
console.log(msg);
};
// Toggle debug log with 'P'
window.addEventListener('keydown', (e) => {
if (e.code === 'KeyP') {
const logDiv = document.getElementById('debug-log');
if (logDiv) {
logDiv.style.display = logDiv.style.display === 'none' ? 'block' : 'none';
}
}
});
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', () => {

View File

@@ -2,7 +2,8 @@ import { defineConfig } from 'vite';
export default defineConfig({
server: {
host: '0.0.0.0',
port: 5173,
},
strictPort: true,
host: true
}
});