feat: Migrate to Vite build system, update dependencies, and refine graphics setup with debugging aids.

This commit is contained in:
2026-01-03 07:09:19 +00:00
parent 5b7edf0729
commit ad5b025a8b
37 changed files with 44297 additions and 360 deletions

View File

@@ -39,7 +39,7 @@ export class Game {
loop(time) {
requestAnimationFrame(this.loop.bind(this));
const dt = Math.min((time - this.lastTime) / 1000, 0.1); // Cap dt
const dt = this.lastTime === 0 ? 0 : Math.min((time - this.lastTime) / 1000, 0.1); // Cap dt
this.lastTime = time;
if (this.isRunning) {

View File

@@ -4,23 +4,38 @@ export class Graphics {
constructor() {
// Main scene rendering
this.scene = new THREE.Scene();
this.scene.fog = new THREE.Fog(0x000000, 2, 15);
this.scene.background = new THREE.Color(0x000000);
this.scene.fog = new THREE.Fog(0x111122, 2, 15);
this.scene.background = new THREE.Color(0x111122); // Dark blue background instead of black
this.camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 100);
// Real Screen Renderer
this.renderer = new THREE.WebGLRenderer({ antialias: false });
this.renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('game-container').appendChild(this.renderer.domElement);
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.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');
}
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.lookAt(0, 0, 0);
// --- Retro Pipeline Setup ---
// 1. Off-screen Render Target (Small Resolution)
// We render the 3D scene here first.
this.targetWidth = 320;
this.targetHeight = 240;
this.renderTarget = new THREE.WebGLRenderTarget(this.targetWidth, this.targetHeight, {
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
@@ -38,7 +53,7 @@ export class Graphics {
const postMaterial = new THREE.ShaderMaterial({
uniforms: {
tDiffuse: { value: this.renderTarget.texture },
colorDepth: { value: 32.0 } // 32 levels per channel (5-bit)
colorDepth: { value: 16.0 } // 16 levels per channel (4-bit per channel - 4096 colors)
},
vertexShader: `
varying vec2 vUv;
@@ -53,8 +68,8 @@ export class Graphics {
varying vec2 vUv;
void main() {
vec4 tex = texture2D(tDiffuse, vUv);
// Quantize color
vec3 color = floor(tex.rgb * colorDepth) / colorDepth;
// 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);
}
`
@@ -74,7 +89,7 @@ export class Graphics {
handleResize() {
const aspect = window.innerWidth / window.innerHeight;
// Update 3D Camera
this.camera.aspect = aspect;
this.camera.updateProjectionMatrix();
@@ -89,6 +104,17 @@ 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);
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);
@@ -96,5 +122,6 @@ export class Graphics {
// 2. Render Post-Processing Quad to Screen
this.renderer.setRenderTarget(null);
this.renderer.render(this.postScene, this.postCamera);
*/
}
}

View File

@@ -1,5 +1,5 @@
import * as THREE from 'three';
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';
import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls.js';
export class Player {
constructor(camera, colliders) {
@@ -20,8 +20,23 @@ export class Player {
this.moveRight = false;
this.velocity = new THREE.Vector3();
this.direction = new THREE.Vector3();
this.flashlightOn = true; // Started as ON
this.setupInput();
this.setupFlashlight();
}
setupFlashlight() {
this.flashlight = new THREE.SpotLight(0xffffff, 10);
this.flashlight.angle = Math.PI / 6;
this.flashlight.penumbra = 0.3;
this.flashlight.decay = 2;
this.flashlight.distance = 15;
this.camera.add(this.flashlight);
this.flashlight.position.set(0, 0, 0);
this.flashlight.target.position.set(0, 0, -1);
this.camera.add(this.flashlight.target);
}
setupInput() {
@@ -31,6 +46,7 @@ export class Player {
case 'KeyA': this.moveLeft = true; break;
case 'KeyS': this.moveBackward = true; break;
case 'KeyD': this.moveRight = true; break;
case 'KeyF': this.toggleFlashlight(); break;
}
};
@@ -47,6 +63,14 @@ export class Player {
document.addEventListener('keyup', onKeyUp);
}
toggleFlashlight() {
if (!this.controls.isLocked) return; // Only toggle when game is active
this.flashlightOn = !this.flashlightOn;
if (this.flashlight) {
this.flashlight.visible = this.flashlightOn;
}
}
lockControls() {
this.controls.lock();
}
@@ -105,5 +129,10 @@ export class Player {
// Keep player on ground
playerPos.y = this.height;
// Flashlight flicker effect (subtle)
if (this.flashlight && this.flashlightOn) {
this.flashlight.intensity = 10 + Math.random() * 0.5;
}
}
}

View File

@@ -7,15 +7,14 @@ export class World {
}
load() {
// Basic lighting
const ambientLight = new THREE.AmbientLight(0x404040, 0.5); // Dim ambient
this.scene.add(ambientLight);
// Grid helper for depth
this.scene.add(new THREE.GridHelper(20, 20));
// Floor
// Floor (Basic Material - no light needed)
const floorGeo = new THREE.PlaneGeometry(20, 20);
const floorMat = new THREE.MeshStandardMaterial({
const floorMat = new THREE.MeshBasicMaterial({
color: 0x333333,
roughness: 0.8
side: THREE.DoubleSide
});
const floor = new THREE.Mesh(floorGeo, floorMat);
floor.rotation.x = -Math.PI / 2;
@@ -27,10 +26,10 @@ export class World {
this.createWall(-10, 2.5, 0, 20, 5, true); // Left
this.createWall(10, 2.5, 0, 20, 5, true); // Right
// Add a reference cube to see depth
// Add a reference cube (Bright Yellow Basic Material)
const cube = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({ color: 0xff0000 })
new THREE.MeshBasicMaterial({ color: 0xffff00 })
);
cube.position.set(0, 0.5, -5);
this.scene.add(cube);
@@ -39,7 +38,7 @@ export class World {
createWall(x, y, z, width, height, rotate = false) {
const geo = new THREE.BoxGeometry(width, height, 0.5);
const mat = new THREE.MeshStandardMaterial({ color: 0x555555 });
const mat = new THREE.MeshBasicMaterial({ color: 0x555555 });
const wall = new THREE.Mesh(geo, mat);
wall.position.set(x, y, z);
if (rotate) wall.rotation.y = Math.PI / 2;

View File

@@ -1,6 +1,14 @@
window.log = (msg) => {
const logDiv = document.getElementById('debug-log');
if (logDiv) logDiv.innerHTML += `> ${msg}<br>`;
console.log(msg);
};
import { Game } from './Game.js';
window.addEventListener('DOMContentLoaded', () => {
window.log('DOM Content Loaded');
const game = new Game();
game.start();
window.log('Game Started');
});