Shadow Fight: Gatos vs Perros 3D
- samuel gaitan
- 27 jun
- 11 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>Shadow Fight: Gatos vs Perros</title>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Roboto:wght@300;400;700&display=swap" rel="stylesheet">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Orbitron', monospace;
overflow: hidden;
color: white;
}
position: relative;
width: 100vw;
height: 100vh;
}
display: block;
}
#ui {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 100;
}
.health-bar-container {
position: absolute;
top: 20px;
width: 300px;
height: 30px;
border: 3px solid #fff;
border-radius: 15px;
background: rgba(0, 0, 0, 0.7);
overflow: hidden;
}
left: 20px;
}
right: 20px;
}
.health-bar {
width: 100%;
height: 100%;
border-radius: 12px;
transition: width 0.3s ease;
}
.health-cat {
}
.health-dog {
}
.player-name {
position: absolute;
bottom: -25px;
width: 100%;
text-align: center;
font-size: 14px;
font-weight: bold;
}
#round-counter {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.8);
padding: 10px 20px;
border-radius: 20px;
border: 2px solid #ffd700;
font-size: 18px;
font-weight: bold;
color: #ffd700;
}
position: absolute;
bottom: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.8);
padding: 15px;
border-radius: 10px;
font-size: 12px;
line-height: 1.5;
pointer-events: auto;
}
#avatar-selector {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.9);
padding: 30px;
border-radius: 20px;
border: 3px solid #ffd700;
text-align: center;
pointer-events: auto;
}
.avatar-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
margin: 20px 0;
}
.avatar-option {
padding: 20px;
border: 2px solid #333;
border-radius: 15px;
cursor: pointer;
transition: all 0.3s ease;
background: rgba(255, 255, 255, 0.1);
}
.avatar-option:hover {
border-color: #ffd700;
background: rgba(255, 215, 0, 0.2);
transform: scale(1.05);
}
.avatar-option.selected {
border-color: #ffd700;
background: rgba(255, 215, 0, 0.3);
}
.start-btn {
border: none;
padding: 15px 30px;
border-radius: 25px;
color: white;
font-family: 'Orbitron', monospace;
font-weight: bold;
font-size: 16px;
cursor: pointer;
transition: all 0.3s ease;
margin-top: 20px;
}
.start-btn:hover {
transform: scale(1.1);
box-shadow: 0 0 20px rgba(255, 107, 53, 0.5);
}
.combo-display {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 48px;
font-weight: 900;
color: #ffd700;
text-shadow: 0 0 20px rgba(255, 215, 0, 0.8);
opacity: 0;
transition: all 0.5s ease;
pointer-events: none;
}
.combo-display.show {
opacity: 1;
transform: translate(-50%, -50%) scale(1.2);
}
.power-indicator {
position: absolute;
bottom: 80px;
width: 200px;
height: 20px;
border: 2px solid #fff;
border-radius: 10px;
background: rgba(0, 0, 0, 0.7);
overflow: hidden;
}
left: 20px;
}
right: 20px;
}
.power-bar {
height: 100%;
border-radius: 8px;
transition: width 0.3s ease;
width: 0%;
}
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.95);
padding: 40px;
border-radius: 20px;
border: 3px solid #ffd700;
text-align: center;
font-size: 24px;
display: none;
pointer-events: auto;
}
.hidden {
display: none !important;
}
</style>
</head>
<body>
<div id="gameContainer">
<canvas id="gameCanvas"></canvas>
<div id="ui">
<!-- Barras de vida -->
<div id="player1Health" class="health-bar-container">
<div class="health-bar health-cat" id="p1HealthBar"></div>
<div class="player-name">GATO SOMBRA</div>
</div>
<div id="player2Health" class="health-bar-container">
<div class="health-bar health-dog" id="p2HealthBar"></div>
<div class="player-name">PERRO LUCHA</div>
</div>
<!-- Contador de rondas -->
<div id="round-counter">RONDA 1</div>
<!-- Indicadores de poder -->
<div id="player1Power" class="power-indicator">
<div class="power-bar" id="p1PowerBar"></div>
</div>
<div id="player2Power" class="power-indicator">
<div class="power-bar" id="p2PowerBar"></div>
</div>
<!-- Display de combos -->
<div id="comboDisplay" class="combo-display"></div>
<!-- Controles -->
<div id="controls">
<strong>CONTROLES:</strong><br>
<strong>Jugador 1 (Gato):</strong><br>
WASD - Mover | Q - Puño | E - Patada<br>
R - Rayo | T - Super Combo | F - Espada<br><br>
<strong>Jugador 2 (Perro):</strong><br>
↑↓←→ - Mover | P - Puño | O - Patada<br>
I - Rayo | U - Super Combo | L - Espada
</div>
<!-- Selector de avatar -->
<div id="avatar-selector">
<h2 style="color: #ffd700; margin-bottom: 20px;">¡ELIGE TU LUCHADOR!</h2>
<div class="avatar-grid">
<div class="avatar-option" data-type="cat" data-color="orange">
<h3>🐱 GATO NARANJA</h3>
<p>Velocidad: ⭐⭐⭐⭐⭐<br>Poder: ⭐⭐⭐</p>
</div>
<div class="avatar-option" data-type="cat" data-color="black">
<h3>🐱 GATO NEGRO</h3>
<p>Velocidad: ⭐⭐⭐<br>Poder: ⭐⭐⭐⭐⭐</p>
</div>
<div class="avatar-option" data-type="dog" data-color="brown">
<h3>🐶 PERRO CAFÉ</h3>
<p>Velocidad: ⭐⭐⭐<br>Poder: ⭐⭐⭐⭐</p>
</div>
<div class="avatar-option" data-type="dog" data-color="white">
<h3>🐶 PERRO BLANCO</h3>
<p>Velocidad: ⭐⭐⭐⭐<br>Poder: ⭐⭐⭐⭐</p>
</div>
</div>
<button class="start-btn" onclick="startGame()">¡COMENZAR BATALLA!</button>
</div>
<!-- Game Over -->
<div id="gameOver">
<h2 id="winnerText"></h2>
<button class="start-btn" onclick="resetGame()">NUEVA BATALLA</button>
</div>
</div>
</div>
<script>
// Variables globales del juego
let scene, camera, renderer, clock;
let player1, player2;
let gameState = 'menu'; // menu, playing, gameOver
let selectedAvatar = { type: 'cat', color: 'orange' };
let round = 1;
let wins = { player1: 0, player2: 0 };
// Estados de los jugadores
let gameData = {
player1: {
health: 100,
power: 0,
position: { x: -3, y: 0, z: 0 },
isAttacking: false,
isBlocking: false,
combo: 0,
lastAttack: 0
},
player2: {
health: 100,
power: 0,
position: { x: 3, y: 0, z: 0 },
isAttacking: false,
isBlocking: false,
combo: 0,
lastAttack: 0
}
};
// Controles
const keys = {};
const keyMap = {
// Jugador 1 (Gato)
'KeyW': 'p1up',
'KeyS': 'p1down',
'KeyA': 'p1left',
'KeyD': 'p1right',
'KeyQ': 'p1punch',
'KeyE': 'p1kick',
'KeyR': 'p1lightning',
'KeyT': 'p1super',
'KeyF': 'p1sword',
// Jugador 2 (Perro)
'ArrowUp': 'p2up',
'ArrowDown': 'p2down',
'ArrowLeft': 'p2left',
'ArrowRight': 'p2right',
'KeyP': 'p2punch',
'KeyO': 'p2kick',
'KeyI': 'p2lightning',
'KeyU': 'p2super',
'KeyL': 'p2sword'
};
// Inicialización
function init() {
// Configurar Three.js
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('gameCanvas'), antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setClearColor(0x0a0a0a);
clock = new THREE.Clock();
// Configurar escena
setupScene();
setupLights();
// Event listeners
document.addEventListener('keydown', onKeyDown);
document.addEventListener('keyup', onKeyUp);
window.addEventListener('resize', onWindowResize);
// Configurar selector de avatar
setupAvatarSelector();
// Iniciar loop de renderizado
animate();
}
function setupScene() {
// Suelo de arena
const floorGeometry = new THREE.PlaneGeometry(20, 20);
const floorMaterial = new THREE.MeshLambertMaterial({
color: 0x8B4513,
transparent: true,
opacity: 0.8
});
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
floor.receiveShadow = true;
scene.add(floor);
// Fondo épico
const bgGeometry = new THREE.SphereGeometry(50, 32, 16);
const bgMaterial = new THREE.MeshBasicMaterial({
color: 0x1a1a2e,
side: THREE.BackSide,
transparent: true,
opacity: 0.7
});
const background = new THREE.Mesh(bgGeometry, bgMaterial);
scene.add(background);
// Posicionar cámara
camera.position.set(0, 3, 8);
camera.lookAt(0, 1, 0);
}
function setupLights() {
// Luz ambiental
const ambientLight = new THREE.AmbientLight(0x404040, 0.4);
scene.add(ambientLight);
// Luz direccional principal
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 5);
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
scene.add(directionalLight);
// Luces de ambiente dramático
const light1 = new THREE.PointLight(0xff6b35, 0.8, 10);
light1.position.set(-5, 3, 2);
scene.add(light1);
const light2 = new THREE.PointLight(0x4facfe, 0.8, 10);
light2.position.set(5, 3, 2);
scene.add(light2);
}
function createCharacter(type, color, position) {
const group = new THREE.Group();
// Cuerpo principal
const bodyGeometry = new THREE.BoxGeometry(0.8, 1.2, 0.4);
let bodyColor;
if (type === 'cat') {
bodyColor = color === 'orange' ? 0xff6b35 : 0x2c2c2c;
} else {
bodyColor = color === 'brown' ? 0x8B4513 : 0xffffff;
}
const bodyMaterial = new THREE.MeshLambertMaterial({ color: bodyColor });
const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
body.position.y = 1;
body.castShadow = true;
group.add(body);
// Cabeza
const headGeometry = new THREE.SphereGeometry(0.4, 16, 16);
const head = new THREE.Mesh(headGeometry, bodyMaterial);
head.position.y = 1.8;
head.castShadow = true;
group.add(head);
// Orejas distintivas
if (type === 'cat') {
// Orejas puntiagudas de gato
const earGeometry = new THREE.ConeGeometry(0.1, 0.3, 8);
const leftEar = new THREE.Mesh(earGeometry, bodyMaterial);
leftEar.position.set(-0.2, 2.1, 0);
leftEar.castShadow = true;
group.add(leftEar);
const rightEar = new THREE.Mesh(earGeometry, bodyMaterial);
rightEar.position.set(0.2, 2.1, 0);
rightEar.castShadow = true;
group.add(rightEar);
// Cola de gato
const tailGeometry = new THREE.CylinderGeometry(0.05, 0.1, 1);
const tail = new THREE.Mesh(tailGeometry, bodyMaterial);
tail.position.set(0, 0.5, -0.5);
tail.rotation.x = Math.PI / 4;
tail.castShadow = true;
group.add(tail);
} else {
// Orejas caídas de perro
const earGeometry = new THREE.SphereGeometry(0.15, 8, 8);
const leftEar = new THREE.Mesh(earGeometry, bodyMaterial);
leftEar.position.set(-0.3, 1.9, 0);
leftEar.scale.y = 0.5;
leftEar.castShadow = true;
group.add(leftEar);
const rightEar = new THREE.Mesh(earGeometry, bodyMaterial);
rightEar.position.set(0.3, 1.9, 0);
rightEar.scale.y = 0.5;
rightEar.castShadow = true;
group.add(rightEar);
// Cola de perro
const tailGeometry = new THREE.CylinderGeometry(0.08, 0.05, 0.8);
const tail = new THREE.Mesh(tailGeometry, bodyMaterial);
tail.position.set(0, 0.8, -0.4);
tail.rotation.x = -Math.PI / 6;
tail.castShadow = true;
group.add(tail);
}
// Brazos
const armGeometry = new THREE.CylinderGeometry(0.1, 0.15, 0.8);
const leftArm = new THREE.Mesh(armGeometry, bodyMaterial);
leftArm.position.set(-0.5, 1, 0);
leftArm.castShadow = true;
group.add(leftArm);
const rightArm = new THREE.Mesh(armGeometry, bodyMaterial);
rightArm.position.set(0.5, 1, 0);
rightArm.castShadow = true;
group.add(rightArm);
// Piernas
const legGeometry = new THREE.CylinderGeometry(0.12, 0.15, 0.8);
const leftLeg = new THREE.Mesh(legGeometry, bodyMaterial);
leftLeg.position.set(-0.2, 0.4, 0);
leftLeg.castShadow = true;
group.add(leftLeg);
const rightLeg = new THREE.Mesh(legGeometry, bodyMaterial);
rightLeg.position.set(0.2, 0.4, 0);
rightLeg.castShadow = true;
group.add(rightLeg);
// Posicionar el grupo
group.position.set(position.x, position.y, position.z);
// Agregar propiedades personalizadas
group.userData = {
type: type,
color: color,
isAnimating: false,
animationTime: 0,
originalPosition: {...position}
};
return group;
}
function setupAvatarSelector() {
const options = document.querySelectorAll('.avatar-option');
options.forEach(option => {
option.addEventListener('click', () => {
options.forEach(opt => opt.classList.remove('selected'));
option.classList.add('selected');
selectedAvatar = {
type: option.dataset.type,
color: option.dataset.color
};
});
});
// Seleccionar primera opción por defecto
options[0].classList.add('selected');
}
function startGame() {
gameState = 'playing';
document.getElementById('avatar-selector').classList.add('hidden');
// Crear personajes
if (player1) scene.remove(player1);
if (player2) scene.remove(player2);
player1 = createCharacter(selectedAvatar.type, selectedAvatar.color, gameData.player1.position);
player2 = createCharacter(
selectedAvatar.type === 'cat' ? 'dog' : 'cat',
selectedAvatar.type === 'cat' ? 'brown' : 'orange',
gameData.player2.position
);
scene.add(player1);
scene.add(player2);
// Resetear estado del juego
resetGameData();
updateUI();
}
function resetGameData() {
gameData.player1.health = 100;
gameData.player1.power = 0;
gameData.player1.combo = 0;
gameData.player2.health = 100;
gameData.player2.power = 0;
gameData.player2.combo = 0;
}
function onKeyDown(event) {
const action = keyMap[event.code];
if (action && gameState === 'playing') {
keys[action] = true;
handleAction(action);
}
}
function onKeyUp(event) {
const action = keyMap[event.code];
if (action) {
keys[action] = false;
}
}
function handleAction(action) {
const player = action.startsWith('p1') ? 'player1' : 'player2';
const character = action.startsWith('p1') ? player1 : player2;
const opponent = action.startsWith('p1') ? 'player2' : 'player1';
const opponentChar = action.startsWith('p1') ? player2 : player1;
if (action.includes('punch')) {
performAttack(player, opponent, character, opponentChar, 'punch', 15);
} else if (action.includes('kick')) {
performAttack(player, opponent, character, opponentChar, 'kick', 20);
} else if (action.includes('lightning')) {
if (gameData[player].power >= 50) {
performSpecialAttack(player, opponent, character, opponentChar, 'lightning', 35);
gameData[player].power -= 50;
}
} else if (action.includes('super')) {
if (gameData[player].power >= 100) {
performSpecialAttack(player, opponent, character, opponentChar, 'super', 50);
gameData[player].power = 0;
}
} else if (action.includes('sword')) {
if (gameData[player].power >= 30) {
performSpecialAttack(player, opponent, character, opponentChar, 'sword', 25);
gameData[player].power -= 30;
}
}
}
function performAttack(attackerKey, defenderKey, attackerChar, defenderChar, type, damage) {
if (gameData[attackerKey].isAttacking) return;
gameData[attackerKey].isAttacking = true;
setTimeout(() => gameData[attackerKey].isAttacking = false, 500);
// Animación de ataque
animateAttack(attackerChar, type);
// Verificar distancia
const distance = Math.abs(attackerChar.position.x - defenderChar.position.x);
if (distance < 2) {
// Golpe exitoso
gameData[defenderKey].health -= damage;
gameData[attackerKey].power = Math.min(100, gameData[attackerKey].power + 10);
gameData[attackerKey].combo++;
// Mostrar combo
if (gameData[attackerKey].combo > 1) {
showCombo(gameData[attackerKey].combo);
}
// Animación de impacto
animateHit(defenderChar);
// Partículas de impacto
createImpactEffect(defenderChar.position);
}
updateUI();
checkGameOver();
}
function performSpecialAttack(attackerKey, defenderKey, attackerChar, defenderChar, type, damage) {
if (gameData[attackerKey].isAttacking) return;
gameData[attackerKey].isAttacking = true;
setTimeout(() => gameData[attackerKey].isAttacking = false, 1000);
// Animación especial
animateSpecialAttack(attackerChar, type);
// Efecto siempre golpea en ataques especiales
gameData[defenderKey].health -= damage;
gameData[attackerKey].combo += 2;
showCombo(`${type.toUpperCase()}!`);
animateHit(defenderChar);
createSpecialEffect(attackerChar.position, type);
updateUI();
checkGameOver();
}
function animateAttack(character, type) {
if (!character || character.userData.isAnimating) return;
character.userData.isAnimating = true;
const originalX = character.position.x;
// Movimiento hacia adelante
const direction = character.position.x < 0 ? 1 : -1;
character.position.x += direction * 0.5;
// Rotación de ataque
const targetRotation = type === 'kick' ? Math.PI / 4 : Math.PI / 6;
character.rotation.y = direction * targetRotation;
setTimeout(() => {
character.position.x = originalX;
character.rotation.y = 0;
character.userData.isAnimating = false;
}, 300);
}
function animateSpecialAttack(character, type) {
if (!character || character.userData.isAnimating) return;
character.userData.isAnimating = true;
const originalY = character.position.y;
if (type === 'lightning') {
// Salto con rayo
character.position.y += 1;
character.rotation.z = Math.PI * 2;
} else if (type === 'super') {
// Giro épico
character.rotation.y = Math.PI * 4;
character.scale.set(1.2, 1.2, 1.2);
} else if (type === 'sword') {
// Dash con espada
const direction = character.position.x < 0 ? 1 : -1;
character.position.x += direction * 1.5;
character.rotation.x = Math.PI / 3;
}
setTimeout(() => {
character.position.y = originalY;
character.rotation.set(0, 0, 0);
character.scale.set(1, 1, 1);
if (type === 'sword') {
character.position.x = character.userData.originalPosition.x;
}
character.userData.isAnimating = false;
}, 800);
}
function animateHit(character) {
if (!character) return;
const originalX = character.position.x;
const direction = character.position.x < 0 ? -1 : 1;
character.position.x += direction * 0.3;
setTimeout(() => {
character.position.x = originalX;
}, 200);
}
function createImpactEffect(position) {
const particleCount = 10;
for (let i = 0; i < particleCount; i++) {
const geometry = new THREE.SphereGeometry(0.05, 8, 8);
const material = new THREE.MeshBasicMaterial({
color: Math.random() > 0.5 ? 0xff6b35 : 0xffd700,
transparent: true,
opacity: 0.8
});
const particle = new THREE.Mesh(geometry, material);
particle.position.copy(position);
particle.position.x += (Math.random() - 0.5) * 2;
particle.position.y += Math.random() + 0.5;
particle.position.z += (Math.random() - 0.5) * 2;
scene.add(particle);
// Animar partícula
const velocity = {
x: (Math.random() - 0.5) * 0.2,
y: Math.random() * 0.3 + 0.1,
z: (Math.random() - 0.5) * 0.2
};
let opacity = 0.8;
const animateParticle = () => {
particle.position.x += velocity.x;
particle.position.y += velocity.y;
particle.position.z += velocity.z;
velocity.y -= 0.01; // Gravedad
opacity -= 0.02;
particle.material.opacity = opacity;
if (opacity > 0) {
requestAnimationFrame(animateParticle);
} else {
scene.remove(particle);
}
};
animateParticle();
}
}
function createSpecialEffect(position, type) {
if (type === 'lightning') {
// Efecto de rayo
for (let i = 0; i < 20; i++) {
const geometry = new THREE.CylinderGeometry(0.02, 0.02, Math.random() * 2 + 1);
const material = new THREE.MeshBasicMaterial({
color: 0x00ffff,
transparent: true,
opacity: 0.9
});
const bolt = new THREE.Mesh(geometry, material);
bolt.position.copy(position);
bolt.position.y += Math.random() * 3;
bolt.rotation.z = Math.random() * Math.PI;
scene.add(bolt);
setTimeout(() => scene.remove(bolt), 500);
}
} else if (type === 'super') {
// Efecto de super combo - explosión de energía
const ringGeometry = new THREE.RingGeometry(0.5, 2, 16);
const ringMaterial = new THREE.MeshBasicMaterial({
color: 0xff0080,
transparent: true,
opacity: 0.7,
side: THREE.DoubleSide
});
const ring = new THREE.Mesh(ringGeometry, ringMaterial);
ring.position.copy(position);
ring.rotation.x = -Math.PI / 2;
scene.add(ring);
let scale = 0.1;
const animateRing = () => {
scale += 0.1;
ring.scale.set(scale, scale, scale);
ring.material.opacity = Math.max(0, 0.7 - scale * 0.1);
if (ring.material.opacity > 0) {
requestAnimationFrame(animateRing);
} else {
scene.remove(ring);
}
};
animateRing();
} else if (type === 'sword') {
// Efecto de espada - línea de corte
const lineGeometry = new THREE.PlaneGeometry(3, 0.1);
const lineMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff,
transparent: true,
opacity: 0.9
});
const slash = new THREE.Mesh(lineGeometry, lineMaterial);
slash.position.copy(position);
slash.position.y += 1;
scene.add(slash);
let opacity = 0.9;
const animateSlash = () => {
opacity -= 0.05;
slash.material.opacity = opacity;
slash.rotation.z += 0.1;
if (opacity > 0) {
requestAnimationFrame(animateSlash);
} else {
scene.remove(slash);
}
};
animateSlash();
}
}
function showCombo(text) {
const comboDisplay = document.getElementById('comboDisplay');
comboDisplay.textContent = text;
comboDisplay.classList.add('show');
setTimeout(() => {
comboDisplay.classList.remove('show');
}, 1000);
}
function updateMovement() {
if (gameState !== 'playing') return;
// Movimiento Jugador 1
if (keys.p1left && player1.position.x > -8) {
player1.position.x -= 0.1;
player1.rotation.y = Math.PI / 6;
} else if (keys.p1right && player1.position.x < 8) {
player1.position.x += 0.1;
player1.rotation.y = -Math.PI / 6;
} else {
player1.rotation.y = 0;
}
if (keys.p1up && player1.position.z > -8) {
player1.position.z -= 0.1;
}
if (keys.p1down && player1.position.z < 8) {
player1.position.z += 0.1;
}
// Movimiento Jugador 2
if (keys.p2left && player2.position.x > -8) {
player2.position.x -= 0.1;
player2.rotation.y = Math.PI / 6;
} else if (keys.p2right && player2.position.x < 8) {
player2.position.x += 0.1;
player2.rotation.y = -Math.PI / 6;
} else {
player2.rotation.y = 0;
}
if (keys.p2up && player2.position.z > -8) {
player2.position.z -= 0.1;
}
if (keys.p2down && player2.position.z < 8) {
player2.position.z += 0.1;
}
// Actualizar posiciones en gameData
gameData.player1.position = { ...player1.position };
gameData.player2.position = { ...player2.position };
}
function updateUI() {
// Actualizar barras de vida
const p1Health = Math.max(0, gameData.player1.health);
const p2Health = Math.max(0, gameData.player2.health);
document.getElementById('p1HealthBar').style.width = p1Health + '%';
document.getElementById('p2HealthBar').style.width = p2Health + '%';
// Actualizar barras de poder
document.getElementById('p1PowerBar').style.width = gameData.player1.power + '%';
document.getElementById('p2PowerBar').style.width = gameData.player2.power + '%';
// Actualizar contador de rondas
document.getElementById('round-counter').textContent = `RONDA ${round}`;
}
function checkGameOver() {
if (gameData.player1.health <= 0) {
endRound('player2');
} else if (gameData.player2.health <= 0) {
endRound('player1');
}
}
function endRound(winner) {
wins[winner]++;
if (wins[winner] >= 2) {
// Fin del juego
gameState = 'gameOver';
const winnerText = winner === 'player1' ?
`¡${selectedAvatar.type === 'cat' ? 'GATO' : 'PERRO'} SOMBRA GANA!` :
`¡${selectedAvatar.type === 'cat' ? 'PERRO' : 'GATO'} LUCHA GANA!`;
document.getElementById('winnerText').textContent = winnerText;
document.getElementById('gameOver').style.display = 'block';
} else {
// Siguiente ronda
round++;
resetGameData();
// Resetear posiciones
player1.position.set(-3, 0, 0);
player2.position.set(3, 0, 0);
updateUI();
// Mostrar mensaje de ronda
showCombo(`RONDA ${round}`);
}
}
function resetGame() {
gameState = 'menu';
round = 1;
wins = { player1: 0, player2: 0 };
document.getElementById('gameOver').style.display = 'none';
document.getElementById('avatar-selector').classList.remove('hidden');
// Limpiar escena
if (player1) {
scene.remove(player1);
player1 = null;
}
if (player2) {
scene.remove(player2);
player2 = null;
}
resetGameData();
updateUI();
}
function animate() {
requestAnimationFrame(animate);
const deltaTime = clock.getDelta();
// Actualizar movimiento
updateMovement();
// Animaciones de idle para los personajes
if (player1 && !player1.userData.isAnimating) {
player1.position.y = Math.sin(Date.now() * 0.005) * 0.1;
player1.rotation.z = Math.sin(Date.now() * 0.003) * 0.05;
}
if (player2 && !player2.userData.isAnimating) {
player2.position.y = Math.sin(Date.now() * 0.005 + Math.PI) * 0.1;
player2.rotation.z = Math.sin(Date.now() * 0.003 + Math.PI) * 0.05;
}
// Efectos de luces dinámicas
const time = Date.now() * 0.001;
if (scene.children.length > 0) {
scene.children.forEach(child => {
if (child.type === 'PointLight') {
child.intensity = 0.8 + Math.sin(time * 2) * 0.3;
}
});
}
// Renderizar
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
// Inicializar el juego
init();
</script>
</body>
</html>




Comentarios