versión inicial del juego

This commit is contained in:
2025-12-30 23:24:58 +01:00
commit 7dbc77e75a
34 changed files with 1589 additions and 0 deletions

158
src/view/GameRenderer.js Normal file
View File

@@ -0,0 +1,158 @@
import * as THREE from 'three';
export class GameRenderer {
constructor(containerId) {
this.container = document.getElementById(containerId) || document.body;
// 1. Scene
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0x1a1a1a);
// 2. Renderer
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: false });
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.shadowMap.enabled = true;
this.container.appendChild(this.renderer.domElement);
// 3. Default Lights
this.setupLights();
// Debug Properties
this.scene.add(new THREE.AxesHelper(10)); // Red=X, Green=Y, Blue=Z
// Grid Helper: Size 100, Divisions 100 (1 unit per cell)
const gridHelper = new THREE.GridHelper(100, 100, 0x444444, 0x222222);
this.scene.add(gridHelper);
// 4. Resize Handler
window.addEventListener('resize', this.onWindowResize.bind(this));
// 5. Textures
this.textureLoader = new THREE.TextureLoader();
this.textureCache = new Map();
}
setupLights() {
// Ambient Light (Base visibility)
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
this.scene.add(ambientLight);
// Directional Light (Sun/Moon - creates shadows)
const dirLight = new THREE.DirectionalLight(0xffffff, 0.7);
dirLight.position.set(50, 100, 50);
dirLight.castShadow = true;
this.scene.add(dirLight);
}
onWindowResize() {
if (this.camera) {
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
}
render(camera) {
if (camera) {
this.renderer.render(this.scene, camera);
}
}
getTexture(path) {
if (!this.textureCache.has(path)) {
// NOTE: Using absolute paths from public dir requires leading slash if served from root
// But verify if we need to prepend anything else.
// Assuming served at root /.
const tex = this.textureLoader.load(path,
(t) => console.log(`Texture loaded: ${path}`),
undefined,
(err) => console.error(`Texture failed: ${path}`, err)
);
tex.magFilter = THREE.NearestFilter;
tex.minFilter = THREE.NearestFilter;
tex.colorSpace = THREE.SRGBColorSpace;
this.textureCache.set(path, tex);
}
return this.textureCache.get(path);
}
addTile(cells, type, tileDef, tileInstance) {
// cells: Array of {x, y} global coordinates
// tileDef: The definition object (has textures, dimensions)
// tileInstance: The instance object (has x, y, rotation, id)
console.log(`Rendering Tile [${type}] with ${cells.length} cells.`);
const isRoom = type === 'room' || type === 'room_objective' || type === 'room_dungeon';
// 1. Draw individual Cells (The Grill)
cells.forEach(cell => {
const geometry = new THREE.BoxGeometry(1, 0.5, 1);
const material = new THREE.MeshStandardMaterial({
color: isRoom ? 0x4444ff : 0xaaaaaa,
roughness: 0.8,
metalness: 0.1,
transparent: true,
opacity: 0.5
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(cell.x, 0, -cell.y);
const edges = new THREE.EdgesGeometry(geometry);
const line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ color: 0x000000 }));
mesh.add(line);
this.scene.add(mesh);
});
// 2. Draw Texture Plane (The Image)
if (tileDef && tileInstance && tileDef.textures && tileDef.textures.length > 0) {
const texturePath = tileDef.textures[0];
console.log(`[GameRenderer] Loading texture ${texturePath} for tile`, tileDef.id);
const texture = this.getTexture(texturePath);
const w = tileDef.width;
const l = tileDef.length;
// Create Plane
const geometry = new THREE.PlaneGeometry(w, l);
const material = new THREE.MeshBasicMaterial({
map: texture,
transparent: true,
side: THREE.DoubleSide,
alphaTest: 0.1
});
const plane = new THREE.Mesh(geometry, material);
// Initial Rotation: Plane X-Y to X-Z
plane.rotation.x = -Math.PI / 2;
// Apply Tile Rotation (N=0, E=1, S=2, W=3 in Y axis)
// We rotate around 0,0 of the plane geometry
// Note: rotation.z is local Z, which after rotX(-90) is Global Y (Vertical)
plane.rotation.z = -tileInstance.rotation * (Math.PI / 2);
// Calculate Center Offset for Positioning
// Visual Center needs to be offset from Tile Origin (x,y)
const midX = (tileDef.width - 1) / 2;
const midY = (tileDef.length - 1) / 2;
// Rotate the offset vector based on tile rotation
let dx, dy;
const r = tileInstance.rotation;
if (r === 0) { dx = midX; dy = midY; }
else if (r === 1) { dx = midY; dy = -midX; }
else if (r === 2) { dx = -midX; dy = -midY; }
else if (r === 3) { dx = -midY; dy = midX; }
const centerX = tileInstance.x + dx;
const centerY = tileInstance.y + dy;
plane.position.set(centerX, 0.55, -centerY);
this.scene.add(plane);
} else {
console.warn(`[GameRenderer] details missing for texture render. def: ${!!tileDef}, inst: ${!!tileInstance}, tex: ${tileDef?.textures?.length}`);
}
}
}