Sos

Spoiler
<!DOCTYPE html> <html lang="vi"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>Kael & Xero: Trỗi Dậy Sau Cái Chết</title> <script src="https://cdn.tailwindcss.com"></script> <style> body { margin: 0; overflow: hidden; background: #050005; color: #fff; font-family: sans-serif; touch-action: none; -webkit-user-select: none; } canvas { display: block; }
    #hud { position: absolute; top: 15px; left: 15px; pointer-events: none; z-index: 10; }
    .bar-container { width: 160px; height: 12px; background: #111; border: 2px solid #333; border-radius: 6px; margin-top: 4px; overflow: hidden; }
    #hp-bar { width: 100%; height: 100%; background: linear-gradient(90deg, #ff0000, #440000); transition: width 0.2s; }
    #charge-bar { width: 0%; height: 100%; background: linear-gradient(90deg, #00ffff, #0055ff); }

    /* Joystick Mobile */
    #joy-base { position: absolute; bottom: 40px; left: 40px; width: 100px; height: 100px; background: rgba(255,255,255,0.05); border: 2px solid rgba(168, 85, 247, 0.4); border-radius: 50%; }
    #joy-stick { position: absolute; top: 25px; left: 25px; width: 50px; height: 50px; background: #a855f7; border-radius: 50%; box-shadow: 0 0 15px #a855f7; pointer-events: none; }

    /* Skill Button - Siêu to để bấm ngay khi hồi sinh */
    #btn-ultimate { 
        position: absolute; bottom: 40px; right: 40px; 
        width: 100px; height: 100px; border-radius: 50%; 
        background: linear-gradient(135deg, #7c3aed, #1e1033);
        border: 4px solid #a855f7; display: flex; align-items: center; 
        justify-content: center; font-weight: bold; font-size: 14px;
        box-shadow: 0 0 20px #a855f7; animation: pulse 2s infinite;
    }
    @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } }

    #msg { position: absolute; top: 20px; right: 20px; width: 220px; background: rgba(0,0,0,0.85); border-left: 4px solid #ef4444; padding: 12px; font-size: 12px; font-style: italic; display: none; z-index: 20; }
    
    .screen-flash { position: absolute; inset: 0; pointer-events: none; z-index: 100; display: none; }
</style>
</head> <body> <div id="hud"> <div class="text-[10px] font-black text-red-500">SINH MỆNH KAEL</div> <div class="bar-container"><div id="hp-bar"></div></div> <div class="text-[9px] text-blue-400 mt-1">NÉN NĂNG LƯỢNG (2 GIÂY):</div> <div class="bar-container"><div id="charge-bar"></div></div> </div> <div id="msg"></div> <div id="screen-flash" class="screen-flash"></div> <div id="joy-base"><div id="joy-stick"></div></div> <div id="btn-ultimate">VẠN CẦU<br>(2 GIÂY)</div>

<canvas id="gameCanvas"></canvas>

<script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; let player = { x: canvas.width/2, y: canvas.height/2, radius: 20, hp: 100, speed: 5.5, alive: true, vx: 0, vy: 0, charging: false, chargeProgress: 0, invincible: 0, // Thời gian bất tử sau hồi sinh clones: [] }; let enemies = []; let bullets = []; let waves = []; // Hiệu ứng sóng xung kích function talk(text, color="#a855f7") { const box = document.getElementById('msg'); box.innerHTML = `<span style="color:${color};font-weight:bold">XERO:</span><br>${text}`; box.style.display = 'block'; setTimeout(() => box.style.display = 'none', 3000); } function triggerReviveBurst() { talk("DẬY ĐI! TA VẪN CÒN ĐÓI!", "#ff0000"); player.alive = true; player.hp = 100; player.invincible = 120; // 2 giây bất tử document.getElementById('hp-bar').style.width = "100%"; // Sóng xung kích hất văng zombie waves.push({ x: player.x, y: player.y, r: 10, maxR: 400 }); // Flash màn hình const flash = document.getElementById('screen-flash'); flash.style.display = 'block'; flash.style.background = 'rgba(255,255,255,0.8)'; setTimeout(() => flash.style.display = 'none', 100); // Đẩy zombie ra xa enemies.forEach(e => { let dx = e.x - player.x; let dy = e.y - player.y; let dist = Math.hypot(dx, dy); if (dist < 300) { e.x += (dx/dist) * 200; e.y += (dy/dist) * 200; e.stun = 60; } }); } function startUltimate() { if (player.charging || !player.alive) return; player.charging = true; player.chargeProgress = 0; player.clones = []; // Triệu hồi 10 phân thân ngay lập tức for(let i=0; i<10; i++) { let angle = (i/10) * Math.PI * 2; player.clones.push({ x: player.x + Math.cos(angle)*70, y: player.y + Math.sin(angle)*70, angle: angle }); } talk("2 GIÂY THÔI... TA SẼ HÚT CẠN SINH KHÍ CỦA CHÚNG!"); } // --- ĐIỀU KHIỂN --- const joyBase = document.getElementById('joy-base'); const joyStick = document.getElementById('joy-stick'); let joyActive = false; joyBase.addEventListener('touchstart', (e) => { if(!player.charging) joyActive = true; e.preventDefault(); }); window.addEventListener('touchmove', (e) => { if (!joyActive || player.charging) return; let touch = e.touches[0]; let rect = joyBase.getBoundingClientRect(); let dx = touch.clientX - (rect.left + 50); let dy = touch.clientY - (rect.top + 50); let dist = Math.min(Math.hypot(dx, dy), 40); let angle = Math.atan2(dy, dx); joyStick.style.transform = `translate(${Math.cos(angle)*dist}px, ${Math.sin(angle)*dist}px)`; player.vx = Math.cos(angle) * (dist/40) * player.speed; player.vy = Math.sin(angle) * (dist/40) * player.speed; }); window.addEventListener('touchend', () => { joyActive = false; joyStick.style.transform = 'translate(0,0)'; player.vx = 0; player.vy = 0; }); document.getElementById('btn-ultimate').addEventListener('touchstart', (e) => { e.preventDefault(); startUltimate(); }); // --- GAME ENGINE --- class Zombie { constructor() { this.x = Math.random() * canvas.width; this.y = Math.random() < 0.5 ? -50 : canvas.height + 50; this.hp = 100; this.stun = 0; } update() { if (this.stun > 0) { this.stun--; return; } // Nếu Kael đang gồng, bị hút về phía Kael nhưng bị khựng (kháng hiệu ứng) if (player.charging) { let d = Math.hypot(player.x - this.x, player.y - this.y); if (d < 250) { this.x += (player.x - this.x) * 0.01; // Bị hút nhẹ this.y += (player.y - this.y) * 0.01; return; // Khựng lại, ko tấn công được } } let angle = Math.atan2(player.y - this.y, player.x - this.x); this.x += Math.cos(angle) * 2.2; this.y += Math.sin(angle) * 2.2; } draw() { ctx.fillStyle = "#16a34a"; // Zombie xanh ctx.beginPath(); ctx.arc(this.x, this.y, 14, 0, Math.PI*2); ctx.fill(); if (this.stun > 0) { // Hiệu ứng choáng ctx.strokeStyle = "white"; ctx.stroke(); } } } function gameLoop() { ctx.fillStyle = '#050005'; ctx.fillRect(0,0, canvas.width, canvas.height); // Vẽ hiệu ứng sóng xung kích waves.forEach((w, i) => { ctx.strokeStyle = `rgba(168, 85, 247, ${1 - w.r/w.maxR})`; ctx.lineWidth = 5; ctx.beginPath(); ctx.arc(w.x, w.y, w.r, 0, Math.PI*2); ctx.stroke(); w.r += 10; if (w.r > w.maxR) waves.splice(i, 1); }); if (player.alive) { if (player.invincible > 0) player.invincible--; if (!player.charging) { player.x += player.vx; player.y += player.vy; } else { // Gồng chiêu 2 giây (tương đương 120 frames tại 60fps) player.chargeProgress += 0.85; // Tăng tốc độ nạp (xấp xỉ 2 giây) document.getElementById('charge-bar').style.width = player.chargeProgress + "%"; // Hiệu ứng hút chân không (các phân thân xoay bàn tay) player.clones.forEach(c => { ctx.strokeStyle = "#00ffff"; ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(c.x, c.y); ctx.lineTo(player.x, player.y); ctx.stroke(); // Bàn tay Xero xoay ctx.fillStyle = "#4c1d95"; let rotX = c.x + Math.cos(Date.now()/50) * 15; let rotY = c.y + Math.sin(Date.now()/50) * 15; ctx.beginPath(); ctx.arc(rotX, rotY, 6, 0, Math.PI*2); ctx.fill(); // Quả cầu nén ctx.fillStyle = "#00ffff"; ctx.beginPath(); ctx.arc(rotX, rotY, (player.chargeProgress/100)*12, 0, Math.PI*2); ctx.fill(); }); if (player.chargeProgress >= 100) { talk("BIẾN MẤT ĐI LŨ RÁC RƯỞI!"); // Bắn vạn cầu for(let i=0; i<20; i++) { let a = (i/20) * Math.PI * 2; bullets.push({ x: player.x, y: player.y, vx: Math.cos(a)*12, vy: Math.sin(a)*12 }); } player.charging = false; player.chargeProgress = 0; player.clones = []; } } // Vẽ Kael ctx.shadowBlur = player.invincible > 0 ? 20 : 0; ctx.shadowColor = "white"; ctx.fillStyle = "#a855f7"; ctx.beginPath(); ctx.arc(player.x, player.y, player.radius, 0, Math.PI*2); ctx.fill(); ctx.shadowBlur = 0; } bullets.forEach((b, i) => { b.x += b.vx; b.y += b.vy; ctx.fillStyle = "#00ffff"; ctx.beginPath(); ctx.arc(b.x, b.y, 12, 0, Math.PI*2); ctx.fill(); if (b.x < 0 || b.x > canvas.width || b.y < 0 || b.y > canvas.height) bullets.splice(i, 1); }); enemies.forEach((e, i) => { e.update(); e.draw(); bullets.forEach(b => { if (Math.hypot(e.x - b.x, e.y - b.y) < 25) e.hp = 0; }); if (e.hp <= 0) enemies.splice(i, 1); // Va chạm zombie đánh Kael if (Math.hypot(player.x - e.x, player.y - e.y) < 30 && player.invincible <= 0) { player.hp = 0; // Một phát chết luôn như bạn nói document.getElementById('hp-bar').style.width = "0%"; player.alive = false; setTimeout(triggerReviveBurst, 1500); // 1.5 giây sau tự hồi sinh nổ tung } }); requestAnimationFrame(gameLoop); } setInterval(() => { if (enemies.length < 15) enemies.push(new Zombie()); }, 1000); talk("Bọn zombie xanh đang tới... Đừng lo, ta sẽ nối lại xương cho ngươi!"); gameLoop(); </script> </body> </html>

Posted Feb 26, 2026, 1:50 PM UTC

03
Loading comments…