This is the function that i want to change:
// Función para colocar un bloque en la posición siguiente en la dirección de la cámara
function placeBlock1() {
// Definir la geometría y el material del bloque
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
// Crear el cubo
const cube = new THREE.Mesh(geometry, material);
// Ajustar la posición del cubo
// Queremos que el bloque se coloque frente al jugador, no en la misma posición
const offsetDistance = 5; // Distancia frente al jugador
const direction = new THREE.Vector3(0, 0, -1).applyQuaternion(camera.quaternion);
cube.position.copy(camera.position).add(direction.multiplyScalar(offsetDistance));
cube.position.x=Math.floor(cube.position.x)
cube.position.y=Math.floor(cube.position.y)
cube.position.z=Math.floor(cube.position.z)
// Añadir el cubo a la escena
scene.add(cube);
// Imprimir la posición para depuración
console.log(`Block placed at: (${cube.position.x}, ${cube.position.y}, ${cube.position.z})`);
}
EDIT 2:
I improved the block placement. Now can place with textures & bad made collision:
[let scene, camera, renderer, controls;
let moveForward = false;
let moveBackward = false;
let moveLeft = false;
let moveRight = false;
let moveUp = false;
let moveDown = false;
let instancedMesh, dirtInstancedMesh; // Declarar globalmente
let destroyedBlocks = {}; // Registrar bloques destruidos
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", 5); // Color amarillo, intensidad 5
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 = 10; // 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
instancedMesh = new THREE.InstancedMesh(cubeGeometry, materials, instancesCount);
instancedMesh.castShadow = true;
instancedMesh.receiveShadow = true;
dirtInstancedMesh = new THREE.InstancedMesh(cubeGeometry, dirtMaterials, dirtInstancesCount);
dirtInstancedMesh.castShadow = true;
dirtInstancedMesh.receiveShadow = true;
collisions = {}
generateWorld = (x1, z1) => {
scene.add(instancedMesh);
scene.add(dirtInstancedMesh);
targetObject.position.set(x1, camera.position.y, z1)
light.position.set(x1 + 20, camera.position.y + 40, z1 + 20);
// 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 / 30, z / 30) * 8 +
noise.simplex2(x / 300, z / 300) * 35 +
noise.simplex2(x / 3000, z / 3000) * 100
); // Altura del terreno
// Verificar si el bloque está destruido
if (!destroyedBlocks[`x${x}y${surface}z${z}`]) {
matrix.makeTranslation(x, surface, z);
instancedMesh.setMatrixAt(index, matrix);
collisions[`x${x}y${surface}z${z}`] = true;
} else {
// Si el bloque no está puesto, moverlo fuera de la vista:
matrix.makeTranslation(9999, 9999, 9999);
instancedMesh.setMatrixAt(index, matrix);
}
for (let i = 1; i < depth; i++) {
if (!destroyedBlocks[`x${x}y${surface - i}z${z}`]) {
matrix.makeTranslation(x, surface - i, z);
dirtInstancedMesh.setMatrixAt(index * depth + i, matrix);
collisions[`x${x}y${surface - i}z${z}`] = true;
} else {
matrix.makeTranslation(9999, 9999, 9999);
dirtInstancedMesh.setMatrixAt(index * depth + i, matrix);
}
}
index++;
}
}
instancedMesh.instanceMatrix.needsUpdate = true;
dirtInstancedMesh.instanceMatrix.needsUpdate = true;
}
removeWorld = () => {
collisions = {}
scene.remove(instancedMesh)
scene.remove(dirtInstancedMesh)
}
targetObject = new THREE.Object3D();
light.target = targetObject;
scene.add(light.target);
generateWorld(0, 0)
setInterval(() => {
light.target.updateMatrix()
light.target.updateMatrixWorld()
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 ‘Space’:
moveUp = true;
break;
case ‘ShiftLeft’:
case ‘ShiftRight’:
moveDown = true;
break;
case ‘KeyE’:
destroyBlocks=true;
break;
case ‘KeyQ’:
placeBlocks=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 ‘Space’:
moveUp = false;
break;
case ‘ShiftLeft’:
case ‘ShiftRight’:
moveDown = false;
break;
case ‘KeyE’:
destroyBlocks=false;
break;
case ‘KeyQ’:
placeBlocks=false;
break;
}
}
// Parámetros de la gravedad:
g = 0.01
ySpeed = 0
jumpSpeed = 0.2
// Función para actualizar la posición del personaje según las teclas presionadas
function updatePosition() {
for(i1 in placedBlocks){
key = i1;
objX=key.split(“x”)[1].split(“y”)[0];
objY=key.split(“y”)[1].split(“z”)[0];
objZ=key.split(“z”)[1];
if(
Math.floor(objX)==Math.floor(camera.position.x)
&&
Math.floor(objY)==Math.floor(camera.position.y)
&&
Math.floor(objZ)==Math.floor(camera.position.z)
){
if(objY<camera.position.y){
ySpeed=g
controls.getObject().position.y += ySpeed
}
if(objY<camera.position.y-3){
ySpeed=g
controls.getObject().position.y += ySpeed
}
}
}
const speed = 0.1; // Velocidad de movimiento del personaje
// Gravedad:
ySpeed -= g
controls.getObject().position.y += ySpeed
if (ySpeed < -0.2) { ySpeed = -0.2 }
// Colisiones:
// Abajo:
if (collisions[
“x” + Math.floor(controls.getObject().position.x) +
“y” + Math.floor(controls.getObject().position.y - speed) +
“z” + Math.floor(controls.getObject().position.z)
]) {
ySpeed = g
controls.getObject().position.y += ySpeed
}
if (collisions[
“x” + Math.floor(controls.getObject().position.x) +
“y” + Math.floor(controls.getObject().position.y - speed - 1) +
“z” + Math.floor(controls.getObject().position.z)
]) {
ySpeed = g
controls.getObject().position.y += ySpeed
}
// Arriba:
if (collisions[
“x” + Math.floor(controls.getObject().position.x) +
“y” + Math.floor(controls.getObject().position.y + speed) +
“z” + Math.floor(controls.getObject().position.z)
]) {
controls.getObject().position.y -= speed
}
if (collisions[
“x” + Math.floor(controls.getObject().position.x) +
“y” + Math.floor(controls.getObject().position.y + speed - 1) +
“z” + Math.floor(controls.getObject().position.z)
]) {
controls.getObject().position.y -= speed
}
// Eje x:
if (collisions[
“x” + Math.floor(controls.getObject().position.x - speed) +
“y” + Math.floor(controls.getObject().position.y) +
“z” + Math.floor(controls.getObject().position.z)
]) {
controls.getObject().position.x += speed
}
if (collisions[
“x” + Math.floor(controls.getObject().position.x - speed) +
“y” + Math.floor(controls.getObject().position.y - 1) +
“z” + Math.floor(controls.getObject().position.z)
]) {
controls.getObject().position.x += speed
}
if (collisions[
“x” + Math.floor(controls.getObject().position.x + speed) +
“y” + Math.floor(controls.getObject().position.y) +
“z” + Math.floor(controls.getObject().position.z)
]) {
controls.getObject().position.x -= speed
}
if (collisions[
“x” + Math.floor(controls.getObject().position.x + speed) +
“y” + Math.floor(controls.getObject().position.y - 1) +
“z” + Math.floor(controls.getObject().position.z)
]) {
controls.getObject().position.x -= speed
}
// Eje z:
if (collisions[
“x” + Math.floor(controls.getObject().position.x) +
“y” + Math.floor(controls.getObject().position.y) +
“z” + Math.floor(controls.getObject().position.z - speed)
]) {
controls.getObject().position.z += speed
}
if (collisions[
“x” + Math.floor(controls.getObject().position.x) +
“y” + Math.floor(controls.getObject().position.y - 1) +
“z” + Math.floor(controls.getObject().position.z - speed)
]) {
controls.getObject().position.z += speed
}
if (collisions[
“x” + Math.floor(controls.getObject().position.x) +
“y” + Math.floor(controls.getObject().position.y) +
“z” + Math.floor(controls.getObject().position.z + speed)
]) {
controls.getObject().position.z -= speed
}
if (collisions[
“x” + Math.floor(controls.getObject().position.x) +
“y” + Math.floor(controls.getObject().position.y - 1) +
“z” + Math.floor(controls.getObject().position.z + speed)
]) {
controls.getObject().position.z -= speed
}
if (collisions[
“x” + Math.floor(controls.getObject().position.x) +
“y” + Math.floor(controls.getObject().position.y) +
“z” + Math.floor(controls.getObject().position.z)
]) {
controls.getObject().position.y += speed * 2
}
if (collisions[
“x” + Math.floor(controls.getObject().position.x) +
“y” + Math.floor(controls.getObject().position.y - 1) +
“z” + Math.floor(controls.getObject().position.z)
]){
controls.getObject().position.y += speed * 2
}
try {
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 (collisions[
“x” + Math.floor(controls.getObject().position.x) +
“y” + Math.floor(controls.getObject().position.y - 2) +
“z” + Math.floor(controls.getObject().position.z)
]) {
ySpeed = jumpSpeed
}
}
if (moveDown) {
// controls.getObject().position.y -= speed;
}
if (destroyBlocks){
destroyBlock();
}
if (placeBlocks===true){
placeBlock1();
}
} catch (e) {}
}
// Función para obtener la rotación de la cámara en el eje Y
function getCameraRotationX() {
const euler = new THREE.Euler();
euler.setFromQuaternion(camera.quaternion, ‘YXZ’);
return euler.x;
}
// 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 obtener la rotación de la cámara en el eje Y
function getCameraRotationZ() {
const euler = new THREE.Euler();
euler.setFromQuaternion(camera.quaternion, ‘YXZ’);
return euler.z;
}
placedBlocks=
// Función para destruir bloques
function destroyBlock() {
const raycaster = new THREE.Raycaster();
const direction = new THREE.Vector3(0, 0, -1);
direction.applyQuaternion(camera.quaternion);
raycaster.set(camera.position, direction);
const intersects = raycaster.intersectObject(instancedMesh);
if (intersects.length > 0) {
const instanceId = intersects[0].instanceId;
const matrix = new THREE.Matrix4();
instancedMesh.getMatrixAt(instanceId, matrix);
const position = new THREE.Vector3();
position.setFromMatrixPosition(matrix);
if(position.distanceTo(camera.position)<5){
// Eliminar el bloque de las colisiones y añadirlo a los bloques destruidos
destroyedBlocks[`x${Math.floor(position.x)}y${Math.floor(position.y)}z${Math.floor(position.z)}`] = true;
delete collisions[`x${Math.floor(position.x)}y${Math.floor(position.y)}z${Math.floor(position.z)}`];
// Mover el bloque fuera de la vista (o puedes optar por otras formas de "destruirlo")
matrix.makeTranslation(9999, 9999, 9999);
instancedMesh.setMatrixAt(instanceId, matrix);
instancedMesh.instanceMatrix.needsUpdate = true;
}
}
const dirtIntersects = raycaster.intersectObject(dirtInstancedMesh);
if (dirtIntersects.length > 0) {
const instanceId = dirtIntersects[0].instanceId;
const matrix = new THREE.Matrix4();
dirtInstancedMesh.getMatrixAt(instanceId, matrix);
const position = new THREE.Vector3();
position.setFromMatrixPosition(matrix);
if(position.distanceTo(camera.position)<5){
// Eliminar el bloque de las colisiones y añadirlo a los bloques destruidos
destroyedBlocks[`x${Math.floor(position.x)}y${Math.floor(position.y)}z${Math.floor(position.z)}`] = true;
delete collisions[`x${Math.floor(position.x)}y${Math.floor(position.y)}z${Math.floor(position.z)}`];
// Mover el bloque fuera de la vista (o puedes optar por otras formas de "destruirlo")
matrix.makeTranslation(9999, 9999, 9999);
dirtInstancedMesh.setMatrixAt(instanceId, matrix);
dirtInstancedMesh.instanceMatrix.needsUpdate = true;
}
}
for(i1 in placedBlocks){
console.log("primer bucle")
for(j=10;j<0;j-=0.1){
key = i1;
objX=key.split("x")[1].split("y")[0];
objY=key.split("y")[1].split("z")[0];
objZ=key.split("z")[1];
console.log("segundo bucle: "+key)
if(
Math.floor(objX)==Math.floor(camera.position.x+Math.sin(getCameraRotationY())*Math.cos(getCameraRotationX())*j)
&&
Math.floor(objY)==Math.floor(camera.position.y+Math.sin(getCameraRotationX())*j)
&&
Math.floor(objZ)==Math.floor(camera.position.z+Math.cos(getCameraRotationY())*Math.cos(getCameraRotationX())*j)
){
scene.remove(placedBlocks[key]);
collisions[key]=false;
}
}
}
}
// Función para colocar un bloque en la posición siguiente en la dirección de la cámara
// Función para colocar un bloque en la posición apuntada por la cámara mediante raycasting
function placeBlock1() {
console.log(“Placing key pressed.”);
// Raycaster para determinar la posición del bloque
const raycaster = new THREE.Raycaster();
raycaster.set(camera.position, camera.getWorldDirection(new THREE.Vector3()));
// Array de intersecciones del rayo con objetos visibles
const intersects = raycaster.intersectObjects(scene.children);
// Si hay intersecciones, colocar el bloque en la primera intersección válida
if (intersects.length > 0) {
const intersect = intersects[0];
const position = new THREE.Vector3().copy(intersect.point).add(intersect.face.normal);
// Redondear la posición a enteros
const newPosition = new THREE.Vector3(
Math.floor(position.x),
Math.floor(position.y),
Math.floor(position.z)
);
// Verificar si ya existe un bloque en la posición calculada
const key = `x${newPosition.x}y${newPosition.y}z${newPosition.z}`;
if (collisions[key]) {
console.log("Block already exists at this position.");
return; // Salir de la función si ya existe un bloque
}
// Crear un nuevo bloque en la posición calculada
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ map: new THREE.TextureLoader().load( "bottom.jpg" ) }); // Color amarillo
const mesh = new THREE.Mesh(geometry, material);
mesh.position.copy(newPosition);
mesh.castShadow=true;
mesh.receiveShadow=true;
// Añadir la nueva posición al sistema de colisiones
collisions[key] = true;
placedBlocks[key] = mesh;
// Añadir el bloque a la escena
scene.add(mesh);
}
}
// 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;](https://)
And this is the result:
This is the file:
script (1).js (21.2 KB)