versión inicial del juego
This commit is contained in:
158
src/view/GameRenderer.js
Normal file
158
src/view/GameRenderer.js
Normal 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}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user