It appears as it when i move the player:
The code is this:
let scene, camera, renderer, controls;
let moveForward = false;
let moveBackward = false;
let moveLeft = false;
let moveRight = false;
let moveUp = false;
let moveDown = false;
function init() {
// Escena
scene = new THREE.Scene();
// Cámara
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(5, 5, 5);
// Renderizador con antialiasing y sombras habilitadas
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // Tipo de sombra suave
renderer.toneMapping = THREE.CineonToneMapping ;
document.body.appendChild(renderer.domElement);
// Definir un color de fondo de la escena
const backgroundColor = new THREE.Color("#08f");
scene.background = backgroundColor;
// Configurar luz direccional simulando la luz del día
const light = new THREE.DirectionalLight("#ff8", 3); // Color amarillo, intensidad 3
light.position.set(20, 40, 20); // Posición de la luz
light.castShadow = true; // Permitir que la luz emita sombras
// Ajustes de sombra
light.shadow.mapSize.width = 4096; // Ancho del mapa de sombra
light.shadow.mapSize.height = 4096; // Alto del mapa de sombra
light.shadow.camera.near = 0.5; // Distancia cercana de la cámara de sombra
light.shadow.camera.far = 1000; // Distancia lejana de la cámara de sombra
light.shadow.camera.left = -200; // Margen izquierdo de la cámara de sombra
light.shadow.camera.right = 200; // Margen derecho de la cámara de sombra
light.shadow.camera.top = 200; // Margen superior de la cámara de sombra
light.shadow.camera.bottom = -200; // Margen inferior de la cámara de sombra
scene.add(light);
// Crear un InstancedMesh para los cubos
const worldSize = 50; // Tamaño del mundo
const cubeSize = 1; // Tamaño de cada cubo
const depth = 15; // Profundidad del terreno
const instancesCount = (worldSize * 2 + 1) * (worldSize * 2 + 1); // Número total de instancias de superficie
const dirtInstancesCount = instancesCount * depth; // Número total de instancias de subsuelo
const cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
const textureLoader = new THREE.TextureLoader();
// Cargar texturas (ajusta las rutas según tus texturas)
const cubeTextureTop = textureLoader.load('top.jpg');
const cubeTextureSide = textureLoader.load('side.jpg');
const cubeTextureBottom = textureLoader.load('bottom.jpg');
// Crear materiales para cada cara del cubo
const materials = [
new THREE.MeshStandardMaterial({ map: cubeTextureSide }), // Cara frontal
new THREE.MeshStandardMaterial({ map: cubeTextureSide }), // Cara trasera
new THREE.MeshStandardMaterial({ map: cubeTextureTop }), // Cara superior
new THREE.MeshStandardMaterial({ map: cubeTextureBottom }), // Cara inferior
new THREE.MeshStandardMaterial({ map: cubeTextureSide }), // Cara derecha
new THREE.MeshStandardMaterial({ map: cubeTextureSide }) // Cara izquierda
];
const dirtMaterials = [
new THREE.MeshStandardMaterial({ map: cubeTextureBottom }), // Cara frontal
new THREE.MeshStandardMaterial({ map: cubeTextureBottom }), // Cara trasera
new THREE.MeshStandardMaterial({ map: cubeTextureBottom }), // Cara superior
new THREE.MeshStandardMaterial({ map: cubeTextureBottom }), // Cara inferior
new THREE.MeshStandardMaterial({ map: cubeTextureBottom }), // Cara derecha
new THREE.MeshStandardMaterial({ map: cubeTextureBottom }) // Cara izquierda
];
// Crear los InstancedMeshes
const instancedMesh = new THREE.InstancedMesh(cubeGeometry, materials, instancesCount);
instancedMesh.castShadow = true;
instancedMesh.receiveShadow = true;
const dirtInstancedMesh = new THREE.InstancedMesh(cubeGeometry, dirtMaterials, dirtInstancesCount);
dirtInstancedMesh.castShadow = true;
dirtInstancedMesh.receiveShadow = true;
generateWorld=(x1,z1)=>{
scene.add(instancedMesh);
scene.add(dirtInstancedMesh);
// Llenar los InstancedMeshes con las posiciones de los cubos
const matrix = new THREE.Matrix4();
let index = 0;
for (let x = x1-worldSize; x <= x1+worldSize; x++) {
for (let z = z1-worldSize; z <= z1+worldSize; z++) {
const surface = Math.floor(
noise.simplex2(x / 35, z / 35) * 6 +
noise.simplex2(x / 150, z / 150) * 30
); // Altura del terreno
matrix.makeTranslation(x, surface, z);
instancedMesh.setMatrixAt(index, matrix);
for (let i = 1; i < depth; i++) {
matrix.makeTranslation(x, surface - i , z);
dirtInstancedMesh.setMatrixAt(index * depth + i, matrix);
}
index++;
}
}
instancedMesh.instanceMatrix.needsUpdate = true;
dirtInstancedMesh.instanceMatrix.needsUpdate = true;
}
removeWorld=()=>{
scene.remove(instancedMesh)
scene.remove(dirtInstancedMesh)
}
generateWorld(0,0)
setInterval(()=>{
removeWorld()
generateWorld(Math.floor(camera.position.x),Math.floor(camera.position.z))
},500)
// Añadir PointerLockControls (opcional para modo espectador)
controls = new THREE.PointerLockControls(camera, document.body);
document.addEventListener('click', () => {
controls.lock();
});
scene.add(controls.getObject()); // Agregar la cámara al mundo
// Manejar el redimensionamiento de la ventana
window.addEventListener('resize', onWindowResize);
// Manejar eventos de teclado para control de movimiento
document.addEventListener('keydown', onKeyDown);
document.addEventListener('keyup', onKeyUp);
// Llamar a la función de renderizado
render();
}
// Función para manejar el redimensionamiento de la ventana
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}
// Función para manejar eventos de teclado (presionar tecla)
function onKeyDown(event) {
switch (event.code) {
case ‘KeyW’:
moveForward = true;
break;
case ‘KeyS’:
moveBackward = true;
break;
case ‘KeyA’:
moveLeft = true;
break;
case ‘KeyD’:
moveRight = true;
break;
case ‘KeyQ’:
moveDown = true;
break;
case ‘KeyE’:
moveUp = true;
break;
}
}
// Función para manejar eventos de teclado (soltar tecla)
function onKeyUp(event) {
switch (event.code) {
case ‘KeyW’:
moveForward = false;
break;
case ‘KeyS’:
moveBackward = false;
break;
case ‘KeyA’:
moveLeft = false;
break;
case ‘KeyD’:
moveRight = false;
break;
case ‘KeyQ’:
moveDown = false;
break;
case ‘KeyE’:
moveUp = false;
break;
}
}
// Función para actualizar la posición del personaje según las teclas presionadas
function updatePosition() {
light.position.set(20+camera.position.x, 40, 20+camera.position.z);
light.updateMatrix() + light.updateMatrixWorld()
light.target.updateMatrix() + light.target.updateMatrixWorld()
const speed = 1; // Velocidad de movimiento del personaje
if (moveForward) {
controls.getObject().position.x -= speed * Math.sin(getCameraRotationY());
controls.getObject().position.z -= speed * Math.cos(getCameraRotationY());
}
if (moveBackward) {
controls.getObject().position.x += speed * Math.sin(getCameraRotationY());
controls.getObject().position.z += speed * Math.cos(getCameraRotationY());
}
if (moveLeft) {
controls.getObject().position.x -= speed * Math.cos(getCameraRotationY());
controls.getObject().position.z += speed * Math.sin(getCameraRotationY());
}
if (moveRight) {
controls.getObject().position.x += speed * Math.cos(getCameraRotationY());
controls.getObject().position.z -= speed * Math.sin(getCameraRotationY());
}
if (moveUp) {
controls.getObject().position.y += speed;
}
if (moveDown) {
controls.getObject().position.y -= speed;
}
}
// Función para obtener la rotación de la cámara en el eje Y
function getCameraRotationY() {
const euler = new THREE.Euler();
euler.setFromQuaternion(camera.quaternion, ‘YXZ’);
return euler.y;
}
// Función para renderizar la escena
function render() {
updatePosition(); // Actualizar posición según teclas presionadas
renderer.render(scene, camera);
requestAnimationFrame(render);
}
// Llamar a la función de inicialización al cargar la página
window.onload = init;