🎮ArcadeLab

David vs Monstruos - Edición Mejorada con Explosiones

by ApexHero69
738 lines28.3 KB
▶ Play
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
    <title>David vs Monstruos - Edición Mejorada con Explosiones</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            user-select: none;
            touch-action: manipulation;
        }

        body {
            background: linear-gradient(135deg, #1a472a, #0a2a1a);
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            font-family: 'Courier New', 'Press Start 2P', monospace;
            padding: 16px;
        }

        .game-container {
            background: #2d5a2c;
            border-radius: 48px;
            padding: 16px;
            box-shadow: 0 20px 35px rgba(0,0,0,0.5);
        }

        canvas {
            display: block;
            margin: 0 auto;
            border-radius: 28px;
            box-shadow: 0 0 0 6px #e8c48a, 0 0 0 12px #8b5a2b;
            cursor: pointer;
            width: 100%;
            height: auto;
            background: linear-gradient(180deg, #87CEEB 0%, #b2e0fa 100%);
        }

        .info-panel {
            display: flex;
            justify-content: space-between;
            align-items: center;
            background: #2c1a0e;
            margin-top: 16px;
            padding: 10px 20px;
            border-radius: 60px;
            color: #ffefb9;
            text-shadow: 2px 2px 0 #5a3a1a;
            flex-wrap: wrap;
            gap: 10px;
        }

        .stat {
            background: #000000aa;
            backdrop-filter: blur(4px);
            padding: 5px 15px;
            border-radius: 32px;
            display: flex;
            align-items: center;
            gap: 8px;
            font-size: 1.2rem;
        }

        .controls {
            display: flex;
            gap: 12px;
            justify-content: center;
            margin-top: 16px;
            flex-wrap: wrap;
        }

        .ctrl-btn {
            background: linear-gradient(145deg, #f0c060, #d4942a);
            border: none;
            font-size: 1.4rem;
            font-weight: bold;
            padding: 12px 24px;
            border-radius: 60px;
            box-shadow: 0 5px 0 #7a4316;
            transition: 0.05s linear;
            cursor: pointer;
            touch-action: manipulation;
            font-family: monospace;
            color: #2d1a04;
            min-width: 90px;
        }

        .ctrl-btn:active {
            transform: translateY(3px);
            box-shadow: 0 2px 0 #7a4316;
        }

        #level-name {
            background: #ffcd7e;
            color: #3a280f;
            padding: 5px 18px;
            border-radius: 40px;
            font-weight: bold;
            font-size: 0.9rem;
        }

        @media (max-width: 700px) {
            .stat { font-size: 0.8rem; padding: 3px 10px; }
            .ctrl-btn { padding: 8px 16px; font-size: 1.1rem; min-width: 70px; }
            #level-name { font-size: 0.7rem; }
        }
    </style>
</head>
<body>
<div>
    <div class="game-container">
        <canvas id="gameCanvas" width="1000" height="600"></canvas>
        <div class="info-panel">
            <div class="stat">❤️ <span id="healthDisplay">5</span></div>
            <div class="stat">🪨 <span id="stonesDisplay">∞</span></div>
            <div class="stat">🏆 <span id="levelDisplay">1</span> / 4</div>
            <div id="level-name">🐝 PANAL DE ABEJAS</div>
        </div>
        <div class="controls">
            <button class="ctrl-btn" id="btnLeft">◀ IZQ</button>
            <button class="ctrl-btn" id="btnRight">DER ▶</button>
            <button class="ctrl-btn" id="btnJump">▲ SALTO</button>
            <button class="ctrl-btn" id="btnThrow">🎯 LANZAR</button>
        </div>
        <div style="text-align: center; margin-top: 10px; color: #eedd99; font-size: 0.7rem;">
            💥 Las abejas explotan al recibir golpe | 5 vidas | Piedras infinitas
        </div>
    </div>
</div>

<script>
    (function(){
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        canvas.width = 1000;
        canvas.height = 600;

        // ========== ESTADO DEL JUEGO ==========
        let currentLevel = 1;
        let health = 5;
        let monsterHits = 0;
        let gameActive = true;
        let gameWin = false;
        
        // ========== JUGADOR ==========
        let player = {
            x: 80,
            y: 500,
            vx: 0,
            vy: 0,
            width: 45,
            height: 55,
            onGround: true,
            facingRight: true
        };
        
        const GRAVITY = 0.7;
        const JUMP_POWER = -11;
        const WALK_SPEED = 5.2;
        const MAX_SPEED = 7;
        
        // ========== MONSTRUO ==========
        let monster = { x: 750, y: 430, width: 110, height: 120 };
        
        // ========== PROYECTILES ==========
        let projectiles = [];
        let explosions = []; // Array para efectos de explosión
        
        let playerProjectile = null;
        let throwCooldown = 0;
        const THROW_COOLDOWN_MAX = 20;
        
        // ========== OTROS ==========
        let invincibleTimer = 0;
        let attackCooldown = 0;
        let moveLeft = false, moveRight = false;
        let jumpRequested = false;
        
        // ========== CONFIGURACIÓN MONSTRUOS ==========
        const monsterVisuals = {
            1: { name: "🐝 PANAL DE ABEJAS", attack: "ENJAMBRE", color1: "#e8a735", color2: "#c97e2a", eyeColor: "#ffdd77" },
            2: { name: "🦁 LEÓN SABANERO", attack: "ZARPAZO", color1: "#e0a060", color2: "#b5622a", eyeColor: "#ffcc44" },
            3: { name: "🐻 OSO PARDO", attack: "PISOTÓN", color1: "#8b5e3c", color2: "#5a3a1a", eyeColor: "#d4a259" },
            4: { name: "🏹 GOLIAT GIGANTE", attack: "LANZA", color1: "#7a5a3a", color2: "#4a2e1a", eyeColor: "#c9a87b" }
        };
        
        const ground = { y: 540, height: 60 };
        
        function updateUI() {
            document.getElementById('healthDisplay').innerText = health;
            document.getElementById('stonesDisplay').innerHTML = "∞";
            document.getElementById('levelDisplay').innerText = currentLevel;
            document.getElementById('level-name').innerHTML = monsterVisuals[currentLevel].name;
        }
        
        function initLevel() {
            player.x = 80;
            player.y = ground.y - player.height;
            player.vy = 0;
            player.vx = 0;
            monsterHits = 0;
            projectiles = [];
            explosions = [];
            playerProjectile = null;
            invincibleTimer = 0;
            attackCooldown = 0;
            throwCooldown = 0;
            gameActive = true;
            gameWin = false;
            updateUI();
        }
        
        function nextLevel() {
            if(currentLevel < 4) {
                currentLevel++;
                initLevel();
            } else {
                gameWin = true;
                gameActive = false;
            }
        }
        
        // ========== LANZAR PIEDRA ==========
        function throwStone() {
            if(!gameActive) return;
            if(throwCooldown > 0) return;
            if(playerProjectile && playerProjectile.active) return;
            
            playerProjectile = {
                x: player.x + (player.facingRight ? player.width : -10),
                y: player.y + 25,
                vx: player.facingRight ? 12 : -12,
                vy: -2,
                active: true,
                radius: 10
            };
            throwCooldown = THROW_COOLDOWN_MAX;
        }
        
        // ========== CREAR EXPLOSIÓN ==========
        function addExplosion(x, y) {
            explosions.push({
                x: x,
                y: y,
                radius: 15,
                frames: 12,
                maxFrames: 12
            });
        }
        
        // ========== FÍSICA JUGADOR ==========
        function updatePlayerPhysics() {
            if(moveLeft && !moveRight) {
                player.vx = -WALK_SPEED;
                player.facingRight = false;
            } else if(moveRight && !moveLeft) {
                player.vx = WALK_SPEED;
                player.facingRight = true;
            } else {
                player.vx *= 0.9;
            }
            
            player.vx = Math.min(Math.max(player.vx, -MAX_SPEED), MAX_SPEED);
            player.vy += GRAVITY;
            player.x += player.vx;
            player.y += player.vy;
            
            if(player.y + player.height >= ground.y) {
                player.y = ground.y - player.height;
                player.vy = 0;
                player.onGround = true;
                if(jumpRequested) {
                    player.vy = JUMP_POWER;
                    player.onGround = false;
                    jumpRequested = false;
                }
            } else {
                player.onGround = false;
            }
            
            if(player.x < 30) player.x = 30;
            if(player.x + player.width > canvas.width - 100) player.x = canvas.width - player.width - 100;
        }
        
        // ========== PROYECTIL JUGADOR (CON EXPLOSIÓN AL GOLPEAR ABEJAS) ==========
        function updatePlayerProjectile() {
            if(!playerProjectile || !playerProjectile.active) return;
            playerProjectile.x += playerProjectile.vx;
            playerProjectile.y += playerProjectile.vy;
            playerProjectile.vy += 0.2;
            
            // Impacto con monstruo
            if(playerProjectile.x + playerProjectile.radius > monster.x &&
               playerProjectile.x - playerProjectile.radius < monster.x + monster.width &&
               playerProjectile.y + playerProjectile.radius > monster.y &&
               playerProjectile.y - playerProjectile.radius < monster.y + monster.height) {
                playerProjectile.active = false;
                monsterHits++;
                
                // Si es el nivel 1 (abejas), crear explosión en el panal
                if(currentLevel === 1) {
                    addExplosion(monster.x + monster.width/2, monster.y + monster.height/2);
                }
                
                if(monsterHits >= 3) {
                    if(currentLevel < 4) nextLevel();
                    else { gameWin = true; gameActive = false; }
                }
                return;
            }
            
            // Impacto con proyectiles enemigos (abejas)
            for(let i = 0; i < projectiles.length; i++) {
                let p = projectiles[i];
                if(p.type === "bee") {
                    if(playerProjectile.x + playerProjectile.radius > p.x &&
                       playerProjectile.x - playerProjectile.radius < p.x + p.w &&
                       playerProjectile.y + playerProjectile.radius > p.y &&
                       playerProjectile.y - playerProjectile.radius < p.y + p.h) {
                        // ¡La abeja explota!
                        playerProjectile.active = false;
                        addExplosion(p.x + p.w/2, p.y + p.h/2);
                        projectiles.splice(i, 1);
                        break;
                    }
                }
            }
            
            if(playerProjectile.x > canvas.width + 50 || playerProjectile.y > canvas.height + 50 ||
               playerProjectile.x < -50) {
                playerProjectile.active = false;
            }
        }
        
        // ========== ACTUALIZAR EXPLOSIONES ==========
        function updateExplosions() {
            for(let i = 0; i < explosions.length; i++) {
                explosions[i].frames--;
                if(explosions[i].frames <= 0) {
                    explosions.splice(i, 1);
                    i--;
                }
            }
        }
        
        // ========== ATAQUE DEL MONSTRUO ==========
        function monsterAttack() {
            if(!gameActive) return;
            if(attackCooldown > 0) { attackCooldown--; return; }
            
            if(currentLevel === 1) { // 3 abejas
                for(let i=0; i<3; i++) {
                    projectiles.push({
                        x: monster.x + 20 + i*25,
                        y: monster.y + 50,
                        vx: -4.5 + Math.random() * 2,
                        vy: 1 + (Math.random() - 0.5) * 3,
                        w: 22, h: 22, type: "bee"
                    });
                }
                attackCooldown = 60;
            } else if(currentLevel === 2) {
                projectiles.push({ x: monster.x+20, y: monster.y+70, vx: -7, vy: -0.5, w: 30, h: 20, type: "claw" });
                projectiles.push({ x: monster.x+60, y: monster.y+80, vx: -6.5, vy: 0.5, w: 30, h: 20, type: "claw" });
                attackCooldown = 55;
            } else if(currentLevel === 3) {
                projectiles.push({ x: monster.x+30, y: monster.y+90, vx: -6, vy: -1, w: 35, h: 25, type: "stomp" });
                attackCooldown = 58;
            } else {
                projectiles.push({ x: monster.x+50, y: monster.y+80, vx: -8, vy: 0, w: 40, h: 12, type: "spear" });
                attackCooldown = 50;
            }
        }
        
        // ========== ACTUALIZAR PROYECTILES ==========
        function updateProjectiles() {
            for(let i=0; i<projectiles.length; i++) {
                let p = projectiles[i];
                p.x += p.vx;
                p.y += p.vy;
                if(p.x + p.w < 0 || p.x > canvas.width || p.y > canvas.height + 100) {
                    projectiles.splice(i,1); i--; continue;
                }
                
                if(invincibleTimer <= 0 && gameActive) {
                    if(player.x < p.x+p.w && player.x+player.width > p.x &&
                       player.y+player.height > p.y && player.y < p.y+p.h) {
                        health--;
                        invincibleTimer = 45;
                        projectiles.splice(i,1); i--;
                        updateUI();
                        if(health <= 0) { gameActive = false; gameWin = false; }
                    }
                }
            }
            if(invincibleTimer > 0) invincibleTimer--;
            if(throwCooldown > 0) throwCooldown--;
        }
        
        // ========== DIBUJADO MEJORADO ==========
        function drawBackground() {
            const grad = ctx.createLinearGradient(0, 0, 0, canvas.height);
            grad.addColorStop(0, "#6ec3e8");
            grad.addColorStop(1, "#b2e0fa");
            ctx.fillStyle = grad;
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            
            // Nubes detalladas
            ctx.fillStyle = "#ffffffdd";
            ctx.shadowBlur = 15;
            ctx.beginPath();
            ctx.ellipse(150, 80, 70, 50, 0, 0, Math.PI*2);
            ctx.ellipse(210, 70, 80, 55, 0, 0, Math.PI*2);
            ctx.ellipse(270, 85, 65, 48, 0, 0, Math.PI*2);
            ctx.fill();
            ctx.beginPath();
            ctx.ellipse(750, 100, 75, 52, 0, 0, Math.PI*2);
            ctx.ellipse(820, 90, 85, 58, 0, 0, Math.PI*2);
            ctx.fill();
            ctx.shadowBlur = 0;
            
            // Suelo
            ctx.fillStyle = "#7cb53e";
            ctx.fillRect(0, ground.y, canvas.width, ground.height);
            ctx.fillStyle = "#5e9630";
            for(let i=0; i<25; i++) {
                ctx.fillRect(i*60, ground.y-6, 45, 12);
                ctx.fillStyle = "#4a7a25";
                ctx.fillRect(i*60+20, ground.y-3, 25, 8);
                ctx.fillStyle = "#5e9630";
            }
            
            // Árbol decorativo
            ctx.fillStyle = "#6b3e1a";
            ctx.fillRect(25, ground.y-180, 40, 180);
            ctx.fillStyle = "#3c8f40";
            ctx.beginPath();
            ctx.ellipse(45, ground.y-200, 55, 65, 0, 0, Math.PI*2);
            ctx.fill();
            ctx.fillStyle = "#2d6a30";
            ctx.beginPath();
            ctx.ellipse(30, ground.y-220, 35, 45, 0, 0, Math.PI*2);
            ctx.fill();
        }
        
        function drawDavid() {
            let x = player.x, y = player.y;
            ctx.save();
            if(!player.facingRight) {
                ctx.translate(x + player.width/2, y + player.height/2);
                ctx.scale(-1, 1);
                ctx.translate(-(x + player.width/2), -(y + player.height/2));
            }
            
            // Túnica
            ctx.fillStyle = "#d4b87a";
            ctx.shadowBlur = 3;
            ctx.beginPath();
            ctx.ellipse(x+22, y+30, 20, 32, 0, 0, Math.PI*2);
            ctx.fill();
            
            // Cabeza
            ctx.fillStyle = "#f5cf9b";
            ctx.beginPath();
            ctx.ellipse(x+22, y+14, 18, 21, 0, 0, Math.PI*2);
            ctx.fill();
            
            // Cabello
            ctx.fillStyle = "#8b5a2b";
            ctx.beginPath();
            ctx.ellipse(x+13, y+6, 11, 13, 0, 0, Math.PI*2);
            ctx.ellipse(x+31, y+6, 11, 13, 0, 0, Math.PI*2);
            ctx.fill();
            
            // Ojos
            ctx.fillStyle = "#2c1a0e";
            ctx.beginPath();
            ctx.arc(x+16, y+13, 3.5, 0, Math.PI*2);
            ctx.arc(x+28, y+13, 3.5, 0, Math.PI*2);
            ctx.fill();
            ctx.fillStyle = "white";
            ctx.beginPath();
            ctx.arc(x+15, y+12, 1.5, 0, Math.PI*2);
            ctx.arc(x+27, y+12, 1.5, 0, Math.PI*2);
            ctx.fill();
            
            // Honda
            ctx.beginPath();
            ctx.moveTo(x+38, y+28);
            ctx.quadraticCurveTo(x+55, y+22, x+48, y+40);
            ctx.lineWidth = 3.5;
            ctx.strokeStyle = "#a57c50";
            ctx.stroke();
            
            ctx.restore();
            
            if(invincibleTimer > 0 && (Math.floor(Date.now()/50)%3 === 0)) {
                ctx.globalAlpha = 0.5;
                ctx.fillStyle = "#ffffaa";
                ctx.fillRect(player.x, player.y, player.width, player.height);
                ctx.globalAlpha = 1;
            }
        }
        
        function drawMonster() {
            let m = monster;
            let data = monsterVisuals[currentLevel];
            ctx.save();
            ctx.shadowBlur = 5;
            
            if(currentLevel === 1) { // Panal detallado
                ctx.fillStyle = data.color1;
                ctx.beginPath();
                ctx.ellipse(m.x+55, m.y+45, 50, 58, 0, 0, Math.PI*2);
                ctx.fill();
                for(let i=0;i<20;i++) {
                    ctx.fillStyle = "#e8b045";
                    ctx.beginPath();
                    ctx.ellipse(m.x+20+(i*7)%90, m.y+15+(i*9)%75, 8, 12, 0, 0, Math.PI*2);
                    ctx.fill();
                }
                ctx.fillStyle = data.eyeColor;
                ctx.beginPath();
                ctx.arc(m.x+35, m.y+42, 9, 0, Math.PI*2);
                ctx.arc(m.x+75, m.y+42, 9, 0, Math.PI*2);
                ctx.fill();
                ctx.fillStyle = "#2c1a0e";
                ctx.beginPath();
                ctx.arc(m.x+33, m.y+40, 4.5, 0, Math.PI*2);
                ctx.arc(m.x+73, m.y+40, 4.5, 0, Math.PI*2);
                ctx.fill();
            } 
            else if(currentLevel === 2) { // León
                ctx.fillStyle = data.color1;
                ctx.beginPath();
                ctx.ellipse(m.x+55, m.y+55, 52, 60, 0, 0, Math.PI*2);
                ctx.fill();
                for(let ang=0; ang<14; ang++) {
                    let rad = ang * Math.PI*2/14;
                    ctx.fillStyle = "#c97a2a";
                    ctx.beginPath();
                    ctx.ellipse(m.x+55+Math.cos(rad)*44, m.y+52+Math.sin(rad)*44, 13, 15, 0, 0, Math.PI*2);
                    ctx.fill();
                }
                ctx.fillStyle = data.eyeColor;
                ctx.beginPath();
                ctx.arc(m.x+38, m.y+52, 9.5, 0, Math.PI*2);
                ctx.arc(m.x+72, m.y+52, 9.5, 0, Math.PI*2);
                ctx.fill();
                ctx.fillStyle = "#2c1a0e";
                ctx.beginPath();
                ctx.arc(m.x+36, m.y+50, 4.5, 0, Math.PI*2);
                ctx.arc(m.x+70, m.y+50, 4.5, 0, Math.PI*2);
                ctx.fill();
            }
            else if(currentLevel === 3) { // Oso
                ctx.fillStyle = data.color1;
                ctx.beginPath();
                ctx.ellipse(m.x+55, m.y+60, 54, 67, 0, 0, Math.PI*2);
                ctx.fill();
                ctx.fillStyle = "#d4a259";
                ctx.beginPath();
                ctx.arc(m.x+38, m.y+72, 8, 0, Math.PI*2);
                ctx.arc(m.x+72, m.y+72, 8, 0, Math.PI*2);
                ctx.fill();
            }
            else { // Goliat
                ctx.fillStyle = data.color1;
                ctx.fillRect(m.x+25, m.y+25, 60, 95);
                ctx.fillStyle = "#4a2e1a";
                ctx.fillRect(m.x+40, m.y, 30, 40);
                ctx.fillStyle = "#d49a5a";
                ctx.beginPath();
                ctx.arc(m.x+42, m.y+68, 8, 0, Math.PI*2);
                ctx.arc(m.x+68, m.y+68, 8, 0, Math.PI*2);
                ctx.fill();
            }
            
            // Barra de vida
            ctx.fillStyle = "#aa2e1e";
            ctx.fillRect(m.x, m.y-18, m.width, 12);
            ctx.fillStyle = "#6fbf4c";
            ctx.fillRect(m.x, m.y-18, (monsterHits/3)*m.width, 12);
            ctx.fillStyle = "white";
            ctx.font = "bold 14px monospace";
            ctx.fillText(`${data.attack} ${monsterHits}/3`, m.x+5, m.y-22);
            ctx.restore();
        }
        
        function drawProjectiles() {
            for(let p of projectiles) {
                if(p.type === "bee") {
                    // Abeja detallada
                    ctx.fillStyle = "#f5bc70";
                    ctx.beginPath();
                    ctx.ellipse(p.x+11, p.y+11, 11, 8, 0, 0, Math.PI*2);
                    ctx.fill();
                    ctx.fillStyle = "#d4942a";
                    for(let i=0;i<2;i++) {
                        ctx.beginPath();
                        ctx.moveTo(p.x+5+i*12, p.y+5);
                        ctx.lineTo(p.x+8+i*6, p.y);
                        ctx.lineTo(p.x+11+i*4, p.y+5);
                        ctx.fill();
                    }
                    ctx.fillStyle = "#2c1a0e";
                    ctx.fillRect(p.x+6, p.y+9, 3, 4);
                    ctx.fillRect(p.x+14, p.y+9, 3, 4);
                    // Ojos
                    ctx.fillStyle = "white";
                    ctx.fillRect(p.x+7, p.y+10, 1.5, 2);
                    ctx.fillRect(p.x+15, p.y+10, 1.5, 2);
                } else if(p.type === "claw") {
                    ctx.fillStyle = "#b5651e";
                    ctx.beginPath();
                    ctx.moveTo(p.x, p.y+10);
                    ctx.lineTo(p.x+15, p.y);
                    ctx.lineTo(p.x+30, p.y+10);
                    ctx.fill();
                } else if(p.type === "stomp") {
                    ctx.fillStyle = "#6b3e1a";
                    ctx.fillRect(p.x, p.y, 32, 22);
                } else {
                    ctx.fillStyle = "#5a3a1a";
                    ctx.fillRect(p.x, p.y+5, 38, 9);
                    ctx.fillRect(p.x+28, p.y, 9, 20);
                }
            }
            
            if(playerProjectile && playerProjectile.active) {
                ctx.fillStyle = "#9a7a58";
                ctx.shadowBlur = 6;
                ctx.beginPath();
                ctx.arc(playerProjectile.x, playerProjectile.y, 10, 0, Math.PI*2);
                ctx.fill();
                ctx.fillStyle = "#5a3a1a";
                ctx.beginPath();
                ctx.arc(playerProjectile.x-2, playerProjectile.y-2, 3.5, 0, Math.PI*2);
                ctx.fill();
                ctx.shadowBlur = 0;
            }
        }
        
        function drawExplosions() {
            for(let e of explosions) {
                let alpha = e.frames / e.maxFrames;
                let size = e.radius * (1 + (1 - alpha) * 1.5);
                ctx.fillStyle = `rgba(255, 100, 0, ${alpha * 0.8})`;
                ctx.beginPath();
                ctx.arc(e.x, e.y, size, 0, Math.PI*2);
                ctx.fill();
                ctx.fillStyle = `rgba(255, 200, 0, ${alpha * 0.9})`;
                ctx.beginPath();
                ctx.arc(e.x, e.y, size * 0.6, 0, Math.PI*2);
                ctx.fill();
                ctx.fillStyle = `rgba(255, 255, 100, ${alpha})`;
                ctx.beginPath();
                ctx.arc(e.x, e.y, size * 0.3, 0, Math.PI*2);
                ctx.fill();
            }
        }
        
        function drawGameMessages() {
            if(!gameActive && !gameWin) {
                ctx.font = "bold 36px monospace";
                ctx.fillStyle = "#d43f1f";
                ctx.shadowBlur = 0;
                ctx.fillText("💀 GAME OVER", canvas.width/2-140, canvas.height/2);
                ctx.font = "18px monospace";
                ctx.fillStyle = "white";
                ctx.fillText("Recarga la página para reintentar", canvas.width/2-180, canvas.height/2+50);
            } else if(gameWin && currentLevel===4 && monsterHits>=3) {
                ctx.font = "bold 36px monospace";
                ctx.fillStyle = "#ffdb7e";
                ctx.fillText("🌟 ¡VICTORIA! 🌟", canvas.width/2-140, canvas.height/2);
                ctx.font = "20px monospace";
                ctx.fillStyle = "#ffefb9";
                ctx.fillText("¡Derrotaste a todos los monstruos!", canvas.width/2-190, canvas.height/2+50);
            }
        }
        
        // ========== BUCLE PRINCIPAL ==========
        function updateGame() {
            if(gameActive && !gameWin) {
                updatePlayerPhysics();
                monsterAttack();
                updateProjectiles();
                updatePlayerProjectile();
                updateExplosions();
                if(health <= 0) { gameActive = false; }
            }
            
            drawBackground();
            drawMonster();
            drawDavid();
            drawProjectiles();
            drawExplosions();
            drawGameMessages();
            
            requestAnimationFrame(updateGame);
        }
        
        // ========== CONTROLES CORREGIDOS ==========
        function attachControls() {
            const leftBtn = document.getElementById('btnLeft');
            const rightBtn = document.getElementById('btnRight');
            const jumpBtn = document.getElementById('btnJump');
            const throwBtn = document.getElementById('btnThrow');
            
            leftBtn.addEventListener('touchstart', (e) => { e.preventDefault(); moveLeft = true; });
            leftBtn.addEventListener('touchend', () => { moveLeft = false; });
            leftBtn.addEventListener('mousedown', () => { moveLeft = true; });
            leftBtn.addEventListener('mouseup', () => { moveLeft = false; });
            
            rightBtn.addEventListener('touchstart', (e) => { e.preventDefault(); moveRight = true; });
            rightBtn.addEventListener('touchend', () => { moveRight = false; });
            rightBtn.addEventListener('mousedown', () => { moveRight = true; });
            rightBtn.addEventListener('mouseup', () => { moveRight = false; });
            
            jumpBtn.addEventListener('touchstart', (e) => { e.preventDefault(); jumpRequested = true; });
            jumpBtn.addEventListener('mousedown', () => { jumpRequested = true; });
            
            throwBtn.addEventListener('touchstart', (e) => { e.preventDefault(); throwStone(); });
            throwBtn.addEventListener('click', () => { throwStone(); });
        }
        
        initLevel();
        attachControls();
        updateGame();
    })();
</script>
</body>
</html>

Game Source: David vs Monstruos - Edición Mejorada con Explosiones

Creator: ApexHero69

Libraries: none

Complexity: complex (738 lines, 28.3 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: david-vs-monstruos-edici-n-mejorada-con--apexhero69" to link back to the original. Then publish at arcadelab.ai/publish.