top of page
Buscar

Juego de Pelea 3D - Artes Marciales



<!DOCTYPE html>

<html lang="es">

<head>

<meta charset="UTF-8">

<title>Juego de Pelea 3D - Artes Marciales</title>

<style>

body {

margin: 0;

overflow: hidden;

background: linear-gradient(135deg, #1a1a2e, #16213e);

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-health { background: linear-gradient(90deg, #00ff00, #ffff00); }

.bot-health { background: linear-gradient(90deg, #ff0000, #ff6600); }

.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;

background: linear-gradient(145deg, #667eea, #764ba2);

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;

background: linear-gradient(145deg, #4facfe, #00f2fe);

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;

background: linear-gradient(145deg, #ff6b6b, #ee5a52);

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>


ree

 
 
 

Comentarios


bottom of page