Meta Description" name="description" />
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Mini GTA Mobile</title>
<style>
body { margin: 0; overflow: hidden; font-family: sans-serif; user-select: none; }
canvas { display: block; }
/* Contenedor de controles táctiles */
#controls {
position: absolute;
bottom: 20px;
left: 20px;
display: grid;
grid-template-columns: repeat(3, 60px);
grid-template-rows: repeat(2, 60px);
gap: 10px;
}
.btn {
width: 60px;
height: 60px;
background: rgba(255, 255, 255, 0.3);
border: 2px solid white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
touch-action: manipulation;
}
.btn:active { background: rgba(255, 255, 255, 0.6); }
#btn-up { grid-column: 2; }
#btn-left { grid-column: 1; grid-row: 2; }
#btn-down { grid-column: 2; grid-row: 2; }
#btn-right { grid-column: 3; grid-row: 2; }
#info {
position: absolute;
top: 10px;
width: 100%;
text-align: center;
color: white;
text-shadow: 1px 1px 2px black;
pointer-events: none;
}
</style>
</head>
<body>
<div id="info">Mini Prototipo 3D Móvil</div>
<div id="controls">
<div class="btn" id="btn-up">↑</div>
<div class="btn" id="btn-left">←</div>
<div class="btn" id="btn-down">↓</div>
<div class="btn" id="btn-right">→</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// --- ESCENA Y CÁMARA ---
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x44aaff);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// --- LUZ ---
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 10, 5);
scene.add(light);
scene.add(new THREE.AmbientLight(0x404040));
// --- SUELO (CIUDAD) ---
const ground = new THREE.Mesh(
new THREE.PlaneGeometry(200, 200),
new THREE.MeshPhongMaterial({ color: 0x333333 })
);
ground.rotation.x = -Math.PI / 2;
scene.add(ground);
// --- JUGADOR (CUBO ROJO) ---
const player = new THREE.Mesh(
new THREE.BoxGeometry(1, 2, 1),
new THREE.MeshPhongMaterial({ color: 0xff4444 })
);
player.position.y = 1;
scene.add(player);
// --- OBJETOS DE RECORRER (EDIFICIOS SIMPLES) ---
for(let i=0; i<10; i++) {
let b = new THREE.Mesh(
new THREE.BoxGeometry(4, 10, 4),
new THREE.MeshPhongMaterial({ color: 0x888888 })
);
b.position.set(Math.random()*40-20, 5, Math.random()*40-20);
scene.add(b);
}
camera.position.set(0, 8, 12);
// --- LÓGICA DE CONTROLES TÁCTILES ---
const moveState = { up: false, down: false, left: false, right: false };
const setupBtn = (id, key) => {
const el = document.getElementById(id);
el.addEventListener('touchstart', (e) => { e.preventDefault(); moveState[key] = true; });
el.addEventListener('touchend', (e) => { e.preventDefault(); moveState[key] = false; });
// Soporte para ratón también
el.addEventListener('mousedown', () => moveState[key] = true);
el.addEventListener('mouseup', () => moveState[key] = false);
};
setupBtn('btn-up', 'up');
setupBtn('btn-down', 'down');
setupBtn('btn-left', 'left');
setupBtn('btn-right', 'right');
// --- BUCLE DE ANIMACIÓN ---
const speed = 0.15;
function animate() {
requestAnimationFrame(animate);
if (moveState.up) player.position.z -= speed;
if (moveState.down) player.position.z += speed;
if (moveState.left) player.position.x -= speed;
if (moveState.right) player.position.x += speed;
// La cámara sigue al jugador suavemente
camera.position.x += (player.position.x - camera.position.x) * 0.1;
camera.position.z += (player.position.z + 10 - camera.position.z) * 0.1;
camera.lookAt(player.position);
renderer.render(scene, camera);
}
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
animate();
</script>
</body>
</html>
2
2
124KB
595KB
2,720.0ms
196.0ms
2,720.0ms