GATO DE BATALLA 3D
- samuel gaitan
- 27 jun
- 4 Min. de lectura
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gato de Batalla 3D</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@700&family=Press+Start+2P&display=swap');
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
transition: background 0.5s ease;
overflow: hidden;
}
/* --- Pantalla de Inicio (Reutilizada) --- */
.start-screen-body {
background-color: #050214;
font-family: 'Cinzel', serif;
}
#start-screen {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
color: white;
text-align: center;
}
#start-screen h1 {
font-size: 3rem;
color: #d4e1ff;
text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #007bff, 0 0 20px #007bff;
margin-bottom: 1rem;
}
#start-button {
font-family: 'Press Start 2P', cursive;
font-size: 1.5rem;
padding: 15px 30px;
color: white;
background: #1e3a8a;
border: 3px solid #92b6f5;
border-radius: 10px;
cursor: pointer;
box-shadow: 0 0 10px #92b6f5, inset 0 0 5px rgba(255, 255, 255, 0.5);
transition: all 0.2s ease-in-out;
margin-top: 2rem;
}
#start-button:hover {
transform: scale(1.05);
box-shadow: 0 0 20px #92b6f5, inset 0 0 8px rgba(255, 255, 255, 0.7);
}
/* --- Estilos del Juego 3D --- */
.game-active-body {
background: #111;
font-family: 'Press Start 2P', cursive;
}
#game-container {
display: none; /* Oculto al inicio */
position: relative;
width: 100vw;
height: 100vh;
}
canvas { display: block; }
#ui-container {
position: absolute; top: 20px; left: 0; width: 100%;
text-align: center;
pointer-events: none; color: white;
}
#score, #message {
font-size: 24px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
}
#message {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 32px;
padding: 20px;
background-color: rgba(0,0,0,0.7);
border-radius: 10px;
}
</style>
</head>
<body class="start-screen-body">
<!-- Pantalla de Inicio (Sin cambios) -->
<div id="start-screen">
<h1>Gato de Batalla 3D</h1>
<p>Mueve el mouse para apuntar, haz clic para disparar.</p>
<button id="start-button">START</button>
</div>
<!-- Contenedor del Juego 3D -->
<div id="game-container">
<div id="ui-container">
<div id="score">Enemigos restantes: 5</div>
</div>
<div id="message"></div>
</div>
<script>
// --- Referencias a Elementos del DOM ---
const startScreen = document.getElementById('start-screen');
const gameContainer = document.getElementById('game-container');
const startButton = document.getElementById('start-button');
// --- Variables Globales del Juego 3D ---
let scene, camera, renderer, player, ground;
let enemies = [];
let lasers = [];
const mousePosition = new THREE.Vector2();
const raycaster = new THREE.Raycaster();
let gameRunning = false;
// --- Evento para Empezar el Juego ---
startButton.addEventListener('click', () => {
startScreen.style.display = 'none';
document.body.className = 'game-active-body';
gameContainer.style.display = 'block';
init3DGame();
});
function init3DGame() {
// --- Configuración de la Escena ---
scene = new THREE.Scene();
scene.background = new THREE.Color(0x100020);
scene.fog = new THREE.Fog(0x100020, 1, 100);
// --- Cámara ---
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 25, 20);
camera.lookAt(0, 0, 0);
// --- Renderizador ---
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
gameContainer.appendChild(renderer.domElement);
// --- Luces ---
const ambientLight = new THREE.AmbientLight(0x4040ff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(10, 20, 5);
directionalLight.castShadow = true;
scene.add(directionalLight);
// --- Crear Objetos del Juego ---
createPlayer();
createGround();
spawnEnemies(5);
// --- Event Listeners ---
window.addEventListener('mousemove', onMouseMove);
window.addEventListener('mousedown', onMouseDown);
window.addEventListener('resize', onWindowResize);
gameRunning = true;
animate();
}
// --- Creación de Objetos ---
function createCat(color) {
const cat = new THREE.Group();
const bodyMat = new THREE.MeshPhongMaterial({ color: color });
// Cuerpo
const body = new THREE.Mesh(new THREE.BoxGeometry(2, 1, 3), bodyMat);
body.position.y = 0.5;
body.castShadow = true;
cat.add(body);
// Cabeza
const head = new THREE.Mesh(new THREE.SphereGeometry(0.8, 16, 16), bodyMat);
head.position.set(0, 1.5, -1);
cat.add(head);
// Orejas
const earMat = new THREE.MeshPhongMaterial({ color: 0x222222 });
const ear1 = new THREE.Mesh(new THREE.ConeGeometry(0.3, 0.7, 8), earMat);
ear1.position.set(-0.5, 2.2, -1);
cat.add(ear1);
const ear2 = ear1.clone();
ear2.position.x = 0.5;
cat.add(ear2);
return cat;
}
function createPlayer() {
player = createCat(0x00ffff); // Gato azul cian
scene.add(player);
}
function createGround() {
const groundMat = new THREE.MeshPhongMaterial({ color: 0x202040, side: THREE.DoubleSide });
const groundGeo = new THREE.PlaneGeometry(100, 100);
ground = new THREE.Mesh(groundGeo, groundMat);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);
}
function spawnEnemies(count) {
for(let i = 0; i < count; i++) {
const enemy = createCat(0xff0000); // Gato rojo
enemy.position.set(
(Math.random() - 0.5) * 60,
0,
(Math.random() - 0.5) * 60 - 10
);
enemies.push(enemy);
scene.add(enemy);
}
updateScore();
}
// --- Lógica del Juego ---
function onMouseMove(event) {
mousePosition.x = (event.clientX / window.innerWidth) * 2 - 1;
mousePosition.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
function onMouseDown() {
if (!gameRunning) return;
const laserMat = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const laserGeo = new THREE.CylinderGeometry(0.1, 0.1, 2, 8);
const laser = new THREE.Mesh(laserGeo, laserMat);
laser.position.copy(player.position);
laser.position.y = 1.5;
// Apuntar el láser
const target = new THREE.Vector3();
raycaster.setFromCamera(mousePosition, camera);
const intersects = raycaster.intersectObject(ground);
if (intersects.length > 0) {
target.copy(intersects[0].point);
}
laser.lookAt(target);
// Propiedad para la dirección del movimiento
laser.velocity = new THREE.Vector3();
target.y = 1.5; // Apuntar en un plano
laser.velocity.subVectors(target, laser.position).normalize().multiplyScalar(1);
lasers.push(laser);
scene.add(laser);
}
function updateScore() {
document.getElementById('score').textContent = `Enemigos restantes: ${enemies.length}`;
}
function showMessage(text) {
const msgEl = document.getElementById('message');
msgEl.textContent = text;
msgEl.style.display = 'block';
}
function checkWinCondition() {
if (enemies.length === 0) {
gameRunning = false;
showMessage("¡VICTORIA! ¡Has derrotado a todos los enemigos!");
}
}
function animate() {
if (!gameRunning) return;
requestAnimationFrame(animate);
// Mover jugador hacia el mouse
raycaster.setFromCamera(mousePosition, camera);
const intersects = raycaster.intersectObject(ground);
if (intersects.length > 0) {
const targetPoint = intersects[0].point;
player.position.lerp(targetPoint, 0.1);
player.lookAt(targetPoint.x, player.position.y, targetPoint.z);
}
// Mover y verificar colisiones de láseres
for (let i = lasers.length - 1; i >= 0; i--) {
const laser = lasers[i];
laser.position.add(laser.velocity);
// Eliminar láseres que se van lejos
if (laser.position.distanceTo(player.position) > 150) {
scene.remove(laser);
lasers.splice(i, 1);
continue;
}
// Colisión con enemigos
for (let j = enemies.length - 1; j >= 0; j--) {
const enemy = enemies[j];
if (laser.position.distanceTo(enemy.position) < 2) {
// Colisión detectada
scene.remove(enemy);
enemies.splice(j, 1);
scene.remove(laser);
lasers.splice(i, 1);
updateScore();
checkWinCondition();
break; // Salir del bucle de enemigos
}
}
}
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
</body>
</html>




Comentarios