Juego de Pelea 3D - Artes Marciales
- samuel gaitan
- 5 jun
- 8 Min. de lectura
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Juego de Pelea 3D - Artes Marciales</title>
<style>
body {
margin: 0;
overflow: hidden;
font-family: 'Arial', sans-serif;
}
canvas { display: block; }
.hud {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 100;
}
.health-bars {
display: flex;
justify-content: space-between;
padding: 20px;
pointer-events: none;
}
.health-bar {
width: 300px;
height: 30px;
background: rgba(0,0,0,0.7);
border: 2px solid #fff;
border-radius: 15px;
overflow: hidden;
}
.health-fill {
height: 100%;
transition: width 0.3s ease;
border-radius: 12px;
}
.player-name, .bot-name {
color: white;
font-weight: bold;
margin-bottom: 5px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
}
.controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
pointer-events: auto;
}
.control-btn {
width: 60px;
height: 60px;
border: none;
border-radius: 12px;
color: white;
font-weight: bold;
font-size: 12px;
cursor: pointer;
transition: all 0.2s ease;
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
}
.control-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0,0,0,0.4);
}
.control-btn:active {
transform: translateY(0);
box-shadow: 0 2px 10px rgba(0,0,0,0.3);
}
.movement-controls {
position: absolute;
bottom: 20px;
left: 20px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 5px;
pointer-events: auto;
}
.move-btn {
width: 50px;
height: 50px;
border: none;
border-radius: 8px;
color: white;
font-weight: bold;
cursor: pointer;
transition: all 0.2s ease;
}
.move-btn:hover {
transform: scale(1.05);
}
.combo-display {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #FFD700;
font-size: 24px;
font-weight: bold;
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
}
.game-title {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
color: white;
z-index: 200;
}
.start-btn {
padding: 15px 30px;
font-size: 18px;
border: none;
border-radius: 25px;
color: white;
cursor: pointer;
margin-top: 20px;
transition: all 0.3s ease;
}
.start-btn:hover {
transform: scale(1.05);
}
</style>
</head>
<body>
<div class="hud">
<div class="health-bars">
<div>
<div class="player-name">JUGADOR</div>
<div class="health-bar">
<div class="health-fill player-health" id="playerHealth" style="width: 100%"></div>
</div>
</div>
<div>
<div class="bot-name">BOT</div>
<div class="health-bar">
<div class="health-fill bot-health" id="botHealth" style="width: 100%"></div>
</div>
</div>
</div>
<div class="combo-display" id="comboDisplay"></div>
<div class="movement-controls">
<div></div>
<button class="move-btn" onclick="movePlayer('forward')">↑</button>
<div></div>
<button class="move-btn" onclick="movePlayer('left')">←</button>
<div></div>
<button class="move-btn" onclick="movePlayer('right')">→</button>
<div></div>
<button class="move-btn" onclick="movePlayer('backward')">↓</button>
<div></div>
</div>
<div class="controls">
<button class="control-btn" onclick="playerPunch()">PUÑO<br>A</button>
<button class="control-btn" onclick="playerKick()">PATADA<br>S</button>
<button class="control-btn" onclick="playerBlock()">BLOQUEO<br>D</button>
<button class="control-btn" onclick="playerCombo()">COMBO<br>RAYO</button>
</div>
</div>
<div class="game-title" id="gameTitle">
<h1>🥋 COMBATE DE ARTES MARCIALES 3D 🥋</h1>
<button class="start-btn" onclick="startGame()">COMENZAR PELEA</button>
</div>
<script>
// Variables del juego
let scene, camera, renderer, player, bot;
let playerHealth = 100, botHealth = 100;
let gameStarted = false;
let isPlayerAttacking = false, isBotAttacking = false;
let playerBlocking = false;
let comboCount = 0;
let lastComboTime = 0;
// Inicialización
function init() {
// Escena
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x1a1a2e, 10, 50);
// Cámara
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.set(0, 8, 15);
camera.lookAt(0, 2, 0);
// Renderer
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild(renderer.domElement);
// Iluminación
const ambientLight = new THREE.AmbientLight(0x404040, 0.4);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(10, 10, 5);
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
scene.add(directionalLight);
// Luz de combate
const spotLight = new THREE.SpotLight(0xff4444, 0.5);
spotLight.position.set(0, 15, 0);
spotLight.castShadow = true;
scene.add(spotLight);
createArena();
createFighters();
setupControls();
animate();
}
function createArena() {
// Suelo principal
const floorGeometry = new THREE.PlaneGeometry(30, 30);
const floorMaterial = new THREE.MeshStandardMaterial({
color: 0x2c3e50,
roughness: 0.8,
metalness: 0.2
});
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
floor.receiveShadow = true;
scene.add(floor);
// Ring de combate
const ringGeometry = new THREE.RingGeometry(8, 10, 32);
const ringMaterial = new THREE.MeshStandardMaterial({
color: 0xffd700,
side: THREE.DoubleSide
});
const ring = new THREE.Mesh(ringGeometry, ringMaterial);
ring.rotation.x = -Math.PI / 2;
ring.position.y = 0.01;
scene.add(ring);
// Paredes del dojo
for(let i = 0; i < 4; i++) {
const wall = new THREE.Mesh(
new THREE.PlaneGeometry(30, 15),
new THREE.MeshStandardMaterial({ color: 0x8b4513 })
);
wall.position.y = 7.5;
wall.rotation.y = (Math.PI / 2) * i;
if(i % 2 === 0) {
wall.position.z = i === 0 ? -15 : 15;
} else {
wall.position.x = i === 1 ? 15 : -15;
}
scene.add(wall);
}
}
function createFighters() {
// Crear jugador
player = createHumanoidFighter(0x00ff00, -5, 0);
player.name = 'player';
// Crear bot
bot = createHumanoidFighter(0xff0000, 5, 0);
bot.name = 'bot';
}
function createHumanoidFighter(color, x, z) {
const fighter = new THREE.Group();
// Cuerpo
const bodyGeometry = new THREE.BoxGeometry(1.2, 1.8, 0.6);
const bodyMaterial = new THREE.MeshStandardMaterial({ color: color });
const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
body.position.y = 1.5;
body.castShadow = true;
fighter.add(body);
// Cabeza
const headGeometry = new THREE.SphereGeometry(0.4, 16, 16);
const headMaterial = new THREE.MeshStandardMaterial({ color: 0xfdbcb4 });
const head = new THREE.Mesh(headGeometry, headMaterial);
head.position.y = 2.7;
head.castShadow = true;
fighter.add(head);
// Brazos
const armGeometry = new THREE.CylinderGeometry(0.15, 0.15, 1.2);
const armMaterial = new THREE.MeshStandardMaterial({ color: 0xfdbcb4 });
const leftArm = new THREE.Mesh(armGeometry, armMaterial);
leftArm.position.set(-0.8, 1.5, 0);
leftArm.castShadow = true;
fighter.add(leftArm);
const rightArm = new THREE.Mesh(armGeometry, armMaterial);
rightArm.position.set(0.8, 1.5, 0);
rightArm.castShadow = true;
fighter.add(rightArm);
// Puños
const fistGeometry = new THREE.SphereGeometry(0.2, 8, 8);
const fistMaterial = new THREE.MeshStandardMaterial({ color: 0xd4af37 });
const leftFist = new THREE.Mesh(fistGeometry, fistMaterial);
leftFist.position.set(-0.8, 0.8, 0);
fighter.add(leftFist);
const rightFist = new THREE.Mesh(fistGeometry, fistMaterial);
rightFist.position.set(0.8, 0.8, 0);
fighter.add(rightFist);
// Piernas
const legGeometry = new THREE.CylinderGeometry(0.2, 0.2, 1.5);
const legMaterial = new THREE.MeshStandardMaterial({ color: 0x333333 });
const leftLeg = new THREE.Mesh(legGeometry, legMaterial);
leftLeg.position.set(-0.3, 0.4, 0);
leftLeg.castShadow = true;
fighter.add(leftLeg);
const rightLeg = new THREE.Mesh(legGeometry, legMaterial);
rightLeg.position.set(0.3, 0.4, 0);
rightLeg.castShadow = true;
fighter.add(rightLeg);
// Pies
const footGeometry = new THREE.BoxGeometry(0.3, 0.2, 0.8);
const footMaterial = new THREE.MeshStandardMaterial({ color: 0x000000 });
const leftFoot = new THREE.Mesh(footGeometry, footMaterial);
leftFoot.position.set(-0.3, -0.1, 0.2);
fighter.add(leftFoot);
const rightFoot = new THREE.Mesh(footGeometry, footMaterial);
rightFoot.position.set(0.3, -0.1, 0.2);
fighter.add(rightFoot);
// Posición inicial
fighter.position.set(x, 0, z);
fighter.userData = {
originalY: 0,
health: 100,
isAttacking: false,
isBlocking: false,
animationTime: 0
};
scene.add(fighter);
return fighter;
}
function setupControls() {
document.addEventListener('keydown', (event) => {
if (!gameStarted) return;
const key = event.key.toLowerCase();
switch(key) {
case 'arrowleft':
case 'a':
movePlayer('left');
break;
case 'arrowright':
case 'd':
movePlayer('right');
break;
case 'arrowup':
case 'w':
movePlayer('forward');
break;
case 'arrowdown':
case 's':
movePlayer('backward');
break;
case ' ':
playerPunch();
break;
case 'shift':
playerKick();
break;
case 'control':
playerBlock();
break;
case 'enter':
playerCombo();
break;
}
});
document.addEventListener('keyup', (event) => {
if (event.key.toLowerCase() === 'control') {
playerBlocking = false;
player.userData.isBlocking = false;
}
});
}
function movePlayer(direction) {
if (!gameStarted || isPlayerAttacking) return;
const speed = 0.3;
const bounds = 8;
switch(direction) {
case 'left':
if (player.position.x > -bounds) player.position.x -= speed;
break;
case 'right':
if (player.position.x < bounds) player.position.x += speed;
break;
case 'forward':
if (player.position.z > -bounds) player.position.z -= speed;
break;
case 'backward':
if (player.position.z < bounds) player.position.z += speed;
break;
}
// Hacer que el jugador mire hacia el bot
player.lookAt(bot.position.x, player.position.y, bot.position.z);
}
function playerPunch() {
if (!gameStarted || isPlayerAttacking) return;
isPlayerAttacking = true;
player.userData.isAttacking = true;
// Animación de puño
animatePunch(player, () => {
checkHit(player, bot, 15, 'Puño');
isPlayerAttacking = false;
player.userData.isAttacking = false;
});
showComboText('¡PUÑO!');
updateCombo();
}
function playerKick() {
if (!gameStarted || isPlayerAttacking) return;
isPlayerAttacking = true;
player.userData.isAttacking = true;
// Animación de patada
animateKick(player, () => {
checkHit(player, bot, 20, 'Patada');
isPlayerAttacking = false;
player.userData.isAttacking = false;
});
showComboText('¡PATADA!');
updateCombo();
}
function playerBlock() {
if (!gameStarted) return;
playerBlocking = true;
player.userData.isBlocking = true;
showComboText('¡BLOQUEO!');
}
function playerCombo() {
if (!gameStarted || isPlayerAttacking) return;
isPlayerAttacking = true;
player.userData.isAttacking = true;
// Combo de rayo - múltiples ataques
animateCombo(player, () => {
checkHit(player, bot, 35, 'Combo de Rayo');
isPlayerAttacking = false;
player.userData.isAttacking = false;
});
showComboText('⚡ COMBO DE RAYO ⚡');
createLightningEffect();
comboCount = 0; // Reset combo
}
function animatePunch(fighter, callback) {
const startTime = Date.now();
const duration = 300;
function animate() {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
// Movimiento hacia adelante
const direction = fighter === player ? 1 : -1;
fighter.position.z += Math.sin(progress * Math.PI) * 0.5 * direction;
if (progress >= 1) {
callback();
} else {
requestAnimationFrame(animate);
}
}
animate();
}
function animateKick(fighter, callback) {
const startTime = Date.now();
const duration = 400;
function animate() {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
// Salto y patada
fighter.position.y = fighter.userData.originalY + Math.sin(progress * Math.PI) * 1;
fighter.rotation.z = Math.sin(progress * Math.PI) * 0.3;
if (progress >= 1) {
fighter.position.y = fighter.userData.originalY;
fighter.rotation.z = 0;
callback();
} else {
requestAnimationFrame(animate);
}
}
animate();
}
function animateCombo(fighter, callback) {
const startTime = Date.now();
const duration = 800;
function animate() {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
// Múltiples ataques con efectos
fighter.rotation.y = Math.sin(progress * Math.PI * 4) * 0.5;
fighter.position.y = fighter.userData.originalY + Math.sin(progress * Math.PI * 6) * 0.3;
if (progress >= 1) {
fighter.rotation.y = 0;
fighter.position.y = fighter.userData.originalY;
callback();
} else {
requestAnimationFrame(animate);
}
}
animate();
}
function checkHit(attacker, target, damage, attackType) {
const distance = attacker.position.distanceTo(target.position);
if (distance < 3) {
let finalDamage = damage;
// Reducir daño si está bloqueando
if (target.userData.isBlocking) {
finalDamage = Math.floor(damage * 0.3);
showComboText('¡BLOQUEADO!');
}
// Aplicar daño
if (target === bot) {
botHealth = Math.max(0, botHealth - finalDamage);
updateHealthBar('bot', botHealth);
} else {
playerHealth = Math.max(0, playerHealth - finalDamage);
updateHealthBar('player', playerHealth);
}
// Efecto de golpe
createHitEffect(target.position);
// Verificar fin del juego
checkGameEnd();
}
}
function botAI() {
if (!gameStarted || isBotAttacking || Math.random() > 0.005) return;
const distance = bot.position.distanceTo(player.position);
const actions = ['punch', 'kick', 'move'];
const action = actions[Math.floor(Math.random() * actions.length)];
switch(action) {
case 'punch':
if (distance < 4) {
isBotAttacking = true;
bot.userData.isAttacking = true;
animatePunch(bot, () => {
checkHit(bot, player, 12, 'Puño Bot');
isBotAttacking = false;
bot.userData.isAttacking = false;
});
}
break;
case 'kick':
if (distance < 5) {
isBotAttacking = true;
bot.userData.isAttacking = true;
animateKick(bot, () => {
checkHit(bot, player, 18, 'Patada Bot');
isBotAttacking = false;
bot.userData.isAttacking = false;
});
}
break;
case 'move':
// Moverse hacia el jugador
const direction = new THREE.Vector3();
direction.subVectors(player.position, bot.position);
direction.normalize();
direction.multiplyScalar(0.1);
bot.position.add(direction);
bot.lookAt(player.position.x, bot.position.y, player.position.z);
break;
}
}
function updateCombo() {
const currentTime = Date.now();
if (currentTime - lastComboTime < 2000) {
comboCount++;
} else {
comboCount = 1;
}
lastComboTime = currentTime;
if (comboCount > 1) {
showComboText(`¡COMBO x${comboCount}!`);
}
}
function createLightningEffect() {
const lightning = new THREE.Group();
for (let i = 0; i < 5; i++) {
const bolt = new THREE.Mesh(
new THREE.CylinderGeometry(0.02, 0.02, Math.random() * 3 + 1),
new THREE.MeshBasicMaterial({ color: 0xffff00, emissive: 0xffff00 })
);
bolt.position.set(
Math.random() * 4 - 2,
Math.random() * 3 + 1,
Math.random() * 4 - 2
);
bolt.rotation.x = Math.random() * Math.PI;
bolt.rotation.z = Math.random() * Math.PI;
lightning.add(bolt);
}
scene.add(lightning);
setTimeout(() => {
scene.remove(lightning);
}, 200);
}
function createHitEffect(position) {
const particles = new THREE.Group();
for (let i = 0; i < 10; i++) {
const particle = new THREE.Mesh(
new THREE.SphereGeometry(0.05),
new THREE.MeshBasicMaterial({ color: 0xff4444 })
);
particle.position.copy(position);
particle.velocity = new THREE.Vector3(
(Math.random() - 0.5) * 2,
Math.random() * 2,
(Math.random() - 0.5) * 2
);
particles.add(particle);
}
scene.add(particles);
const animate = () => {
particles.children.forEach(particle => {
particle.position.add(particle.velocity);
particle.velocity.multiplyScalar(0.95);
particle.material.opacity *= 0.9;
});
if (particles.children[0].material.opacity > 0.1) {
requestAnimationFrame(animate);
} else {
scene.remove(particles);
}
};
animate();
}
function showComboText(text) {
const display = document.getElementById('comboDisplay');
display.textContent = text;
display.style.opacity = '1';
setTimeout(() => {
display.style.opacity = '0';
}, 1000);
}
function updateHealthBar(fighter, health) {
const healthBar = document.getElementById(fighter + 'Health');
healthBar.style.width = health + '%';
}
function checkGameEnd() {
if (playerHealth <= 0) {
showComboText('¡BOT GANA!');
gameStarted = false;
setTimeout(() => location.reload(), 3000);
} else if (botHealth <= 0) {
showComboText('¡JUGADOR GANA!');
gameStarted = false;
setTimeout(() => location.reload(), 3000);
}
}
function startGame() {
gameStarted = true;
document.getElementById('gameTitle').style.display = 'none';
showComboText('¡COMBATE!');
}
function animate() {
requestAnimationFrame(animate);
if (gameStarted) {
botAI();
// Animaciones de respiración
player.userData.animationTime += 0.02;
bot.userData.animationTime += 0.02;
if (!player.userData.isAttacking) {
player.position.y = player.userData.originalY + Math.sin(player.userData.animationTime) * 0.05;
}
if (!bot.userData.isAttacking) {
bot.position.y = bot.userData.originalY + Math.sin(bot.userData.animationTime) * 0.05;
}
}
renderer.render(scene, camera);
}
// Responsividad
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Inicializar juego
init();
</script>
</body>
</html>




Comentarios