|
|
Unblocked Bloons 💯 Ultimate@media (max-width: 760px) .stat font-size: 1rem; .tower-btn padding: 5px 14px; font-size: 1rem; .info-panel gap: 12px; justify-content: center; </style> </head> <body> <div> <div class="game-wrapper"> <canvas id="gameCanvas" width="900" height="540"></canvas> <div class="info-panel"> <div class="stats"> <div class="stat"><span>🎈</span> <span id="livesDisplay">100</span> ❤️</div> <div class="stat"><span>💰</span> <span id="cashDisplay">350</span></div> <div class="stat"><span>🎯</span> <span id="scoreDisplay">0</span></div> </div> <div class="tower-zone"> <button class="tower-btn" id="buyTowerBtn">🏹 DART MONKEY · 150💰</button> <button class="tower-btn reset-btn" id="resetGameBtn">🔄 RESTART</button> </div> <div class="status" id="waveStatus">🌊 WAVE 1 · preparing</div> </div> </div> <div style="text-align: center; margin-top: 14px; font-size: 12px; color:#c2b280;">⚡ click track → build tower | balloons pop = +cash | survive waves!</div> </div> // ---------- GAME DIMENSIONS ---------- const W = 900, H = 540; // path definition (winding road) const waypoints = [ x: 80, y: 120, // start x: 220, y: 120, x: 220, y: 280, x: 500, y: 280, x: 500, y: 420, x: 720, y: 420, x: 720, y: 180, x: 820, y: 180 // end zone ]; // helper: interpolate path length (for bloon movement) function getPathLength() let len = 0; for(let i=0; i<waypoints.length-1; i++) const p1 = waypoints[i]; const p2 = waypoints[i+1]; len += Math.hypot(p2.x-p1.x, p2.y-p1.y); return len; const TOTAL_PATH_LEN = getPathLength(); // get position from t (0..1) function getPathPosition(t) if(t <= 0) return ...waypoints[0]; if(t >= 1) return ...waypoints[waypoints.length-1]; let total = TOTAL_PATH_LEN; let distNeeded = t * total; let accumulated = 0; for(let i=0; i<waypoints.length-1; i++) const p1 = waypoints[i]; const p2 = waypoints[i+1]; const segLen = Math.hypot(p2.x-p1.x, p2.y-p1.y); if(distNeeded <= accumulated + segLen) const localT = (distNeeded - accumulated) / segLen; const x = p1.x + (p2.x-p1.x)*localT; const y = p1.y + (p2.y-p1.y)*localT; return x, y; accumulated += segLen; return ...waypoints[waypoints.length-1]; // ----- GAME STATE ----- let lives = 100; let cash = 350; let totalPopped = 0; // score let wave = 1; let waveInProgress = false; let waveTimer = 0; // delay before spawning next bloon (frames) let bloonsToSpawn = 0; let spawnDelayFrames = 0; // dynamic arrays let bloons = []; let towers = []; // projectile array let projectiles = []; // frame counter for wave logic let frameCounter = 0; // bloon types (stats) const BLOON_TYPES = red: health: 1, speed: 1.8, reward: 20, color: "#E34234", radius: 12, value: 1 , blue: health: 2, speed: 1.5, reward: 35, color: "#4C9AFF", radius: 13, value: 2 , green: health: 3, speed: 1.2, reward: 55, color: "#5FAD41", radius: 14, value: 3 , ; // tower stats const TOWER_PRICE = 150; const TOWER_RANGE = 78; const TOWER_COOLDOWN_MAX = 28; // frames between attacks const TOWER_DAMAGE = 1; // ----- helper functions ----- function addCash(amount) cash += amount; updateUI(); function removeCash(amount) if(cash >= amount) cash -= amount; updateUI(); return true; return false; function loseLife(amount=1) lives -= amount; if(lives <= 0) lives = 0; gameOver(); updateUI(); function updateUI() document.getElementById('livesDisplay').innerText = lives; document.getElementById('cashDisplay').innerText = Math.floor(cash); document.getElementById('scoreDisplay').innerText = totalPopped; function gameOver() waveInProgress = false; bloons = []; projectiles = []; document.getElementById('waveStatus').innerHTML = `💀 GAME OVER 💀 · press RESTART`; // spawn a specific bloon type at start (t=0) function spawnBloon(typeKey) const def = BLOON_TYPES[typeKey]; if(!def) return; bloons.push( type: typeKey, health: def.health, maxHealth: def.health, t: 0.0, speed: def.speed / 100, // per frame advance (~0.018 to 0.012) reward: def.reward, radius: def.radius, color: def.color, value: def.value ); // start wave: determine composition based on wave number function startWave() if(lives <= 0) return; waveInProgress = true; bloonsToSpawn = 0; // wave difficulty: more bloons + stronger types let redCount = Math.min(4 + Math.floor(wave * 0.8), 18); let blueCount = Math.min(1 + Math.floor(wave / 2), 8); let greenCount = Math.min(0 + Math.floor(wave / 4), 6); if(wave >= 3) blueCount = Math.min(2 + Math.floor(wave/2.5), 10); if(wave >= 5) greenCount = Math.min(1 + Math.floor(wave/3.5), 8); let spawnQueue = []; for(let i=0; i<redCount; i++) spawnQueue.push('red'); for(let i=0; i<blueCount; i++) spawnQueue.push('blue'); for(let i=0; i<greenCount; i++) spawnQueue.push('green'); // shuffle for variety for(let i=spawnQueue.length-1; i>0; i--) const j = Math.floor(Math.random()*(i+1)); [spawnQueue[i], spawnQueue[j]] = [spawnQueue[j], spawnQueue[i]]; bloonsToSpawn = spawnQueue.length; // store pending spawns window._waveSpawnQueue = spawnQueue; spawnDelayFrames = 12; // initial delay before first bloon document.getElementById('waveStatus').innerHTML = `🌊 WAVE $wave · incoming! 🎈`; // update wave spawning logic function updateWaveSpawning() if(!waveInProgress) return; if(lives <= 0) return; if(bloonsToSpawn <= 0 && bloons.length === 0 && projectiles.filter(p=>!p.hit).length===0) // wave cleared waveInProgress = false; const waveBonus = 100 + wave * 15; addCash(waveBonus); totalPopped += 15; // bonus for wave clear wave++; updateUI(); document.getElementById('waveStatus').innerHTML = `🏆 WAVE $wave-1 CLEARED! Next wave in 2s 🏆`; // auto start next wave after 2 seconds (60 frames) setTimeout(() => if(lives > 0 && !waveInProgress && bloons.length === 0) startWave(); , 1800); return; if(bloonsToSpawn > 0 && spawnDelayFrames <= 0) if(window._waveSpawnQueue && window._waveSpawnQueue.length) const nextType = window._waveSpawnQueue.shift(); spawnBloon(nextType); bloonsToSpawn--; // dynamic delay between spawns (faster waves = less delay) let delay = Math.max(14, 28 - Math.floor(wave/2)); if(delay < 8) delay = 8; spawnDelayFrames = delay; else bloonsToSpawn = 0; else if(spawnDelayFrames > 0) spawnDelayFrames--; // update bloon movement & endpoint damage function updateBloons() for(let i=0; i<bloons.length; i++) const b = bloons[i]; let newT = b.t + b.speed; if(newT >= 1.0) // reached end -> damage player loseLife(1); bloons.splice(i,1); i--; continue; b.t = newT; // tower attacks function updateTowersAndProjectiles() // tower cooldown update for(let t of towers) if(t.cooldown > 0) t.cooldown--; // attack: find target for(let t of towers) if(t.cooldown > 0) continue; let closest = null; let minDist = TOWER_RANGE + 1; for(let b of bloons) const pos = getPathPosition(b.t); const dx = pos.x - t.x; const dy = pos.y - t.y; const dist = Math.hypot(dx,dy); if(dist < minDist) minDist = dist; closest = b; if(closest) t.cooldown = TOWER_COOLDOWN_MAX; // create projectile that will hit this bloon after flight time const targetBloon = closest; const startPos = x: t.x, y: t.y; const targetPos = getPathPosition(targetBloon.t); projectiles.push( x: startPos.x, y: startPos.y, target: targetBloon, damage: TOWER_DAMAGE, active: true, speed: 7.2, reached: false ); // update projectiles for(let i=0; i<projectiles.length; i++) // tower placement on canvas (click) function tryPlaceTower(mouseX, mouseY) if(lives <= 0) return false; // check not overlapping existing tower (min 32px) for(let t of towers) const dx = t.x - mouseX; const dy = t.y - mouseY; if(Math.hypot(dx,dy) < 28) return false; // avoid placing on the path (simple check: sample 6 points along track near click) for(let tVal = 0; tVal <= 1.0; tVal+=0.05) const pt = getPathPosition(tVal); if(Math.hypot(pt.x - mouseX, pt.y - mouseY) < 19) return false; // check if enough cash if(cash >= TOWER_PRICE) removeCash(TOWER_PRICE); towers.push( x: mouseX, y: mouseY, cooldown: 0, range: TOWER_RANGE ); return true; return false; // reset full game function resetGame() lives = 100; cash = 350; totalPopped = 0; wave = 1; bloons = []; towers = []; projectiles = []; waveInProgress = false; window._waveSpawnQueue = []; bloonsToSpawn = 0; spawnDelayFrames = 0; updateUI(); // start wave after short delay setTimeout(() => if(lives > 0 && !waveInProgress && bloons.length === 0) startWave(); , 100); document.getElementById('waveStatus').innerHTML = `✨ RESTARTED · Wave 1 ✨`; // ---------- DRAW EVERYTHING (unblocked style, vivid) ---------- function draw() ctx.clearRect(0,0,W,H); // background grassy ctx.fillStyle = "#297a4d"; ctx.fillRect(0,0,W,H); // draw path (dirt track) ctx.beginPath(); for(let i=0; i<waypoints.length; i++) if(i===0) ctx.moveTo(waypoints[i].x, waypoints[i].y); else ctx.lineTo(waypoints[i].x, waypoints[i].y); ctx.lineWidth = 32; ctx.strokeStyle = "#bc9a6c"; ctx.shadowBlur = 0; ctx.stroke(); ctx.lineWidth = 6; ctx.strokeStyle = "#e7cfa1"; ctx.setLineDash([12, 18]); ctx.stroke(); ctx.setLineDash([]); // draw path border ctx.lineWidth = 3; ctx.strokeStyle = "#5e3a1c"; ctx.stroke(); // start / end icons ctx.font = "bold 18monospace"; ctx.fillStyle = "#FFE484"; ctx.shadowBlur = 0; ctx.fillText("🏁", waypoints[0].x-16, waypoints[0].y-8); ctx.fillStyle = "#ff8866"; ctx.fillText("🏁", waypoints[waypoints.length-1].x+4, waypoints[waypoints.length-1].y-8); // draw towers (monkey faces!) for(let t of towers) ctx.beginPath(); ctx.arc(t.x, t.y, 18, 0, Math.PI*2); ctx.fillStyle = "#c99e6f"; ctx.fill(); ctx.beginPath(); ctx.arc(t.x-6, t.y-4, 4, 0, Math.PI*2); ctx.arc(t.x+6, t.y-4, 4, 0, Math.PI*2); ctx.fillStyle = "#2f221b"; ctx.fill(); ctx.fillStyle = "white"; ctx.beginPath(); ctx.arc(t.x-7, t.y-6, 1.5, 0, Math.PI*2); ctx.arc(t.x+5, t.y-6, 1.5, 0, Math.PI*2); ctx.fill(); ctx.fillStyle = "#a55828"; ctx.beginPath(); ctx.ellipse(t.x, t.y+4, 6, 4, 0, 0, Math.PI*2); ctx.fill(); ctx.fillStyle = "#654321"; ctx.font = "bold 20px monospace"; ctx.fillText("🐒", t.x-11, t.y+8); // range indicator (semi) ctx.beginPath(); ctx.arc(t.x, t.y, TOWER_RANGE, 0, Math.PI*2); ctx.globalAlpha = 0.1; ctx.fillStyle = "#fcdb6a"; ctx.fill(); ctx.globalAlpha = 1; // bloons: cute balloons with pop animation feel for(let b of bloons) const pos = getPathPosition(b.t); const hpPercent = b.health / b.maxHealth; ctx.beginPath(); ctx.ellipse(pos.x, pos.y, b.radius, b.radius*1.1, 0, 0, Math.PI*2); ctx.fillStyle = b.color; ctx.fill(); ctx.beginPath(); ctx.moveTo(pos.x-4, pos.y+ b.radius-2); ctx.lineTo(pos.x, pos.y+ b.radius+6); ctx.lineTo(pos.x+4, pos.y+ b.radius-2); ctx.fillStyle = "#ad8b4c"; ctx.fill(); ctx.fillStyle = "white"; ctx.font = `bold $Math.floor(b.radius-2)px monospace`; ctx.fillText(b.health, pos.x-5, pos.y+5); // stress lines ctx.beginPath(); ctx.strokeStyle = "#fff3cf"; ctx.lineWidth = 1.5; for(let s=0; s<3; s++) ctx.moveTo(pos.x-9 + s*3, pos.y-6); ctx.lineTo(pos.x-4 + s*2, pos.y-12); ctx.stroke(); // projectiles (darts) for(let p of projectiles) ctx.beginPath(); ctx.moveTo(p.x, p.y); ctx.lineTo(p.x-6, p.y-4); ctx.lineTo(p.x-2, p.y); ctx.fillStyle = "#d4af37"; ctx.fill(); ctx.beginPath(); ctx.arc(p.x, p.y, 3, 0, Math.PI*2); ctx.fillStyle = "#ffb347"; ctx.fill(); // placement preview if hovering (optional) // UI text overlay: range etc. ctx.font = "bold 14px 'Segoe UI'"; ctx.fillStyle = "#f9eec1"; ctx.shadowBlur = 2; ctx.fillText("✦ Click on grass to build tower ✦", 30, 40); ctx.font = "italic 12px monospace"; ctx.fillStyle = "#cbf5c9"; ctx.fillText("Bloons follow the dirt path", W-180, H-18); // main game loop let lastTimestamp = 0; function gameLoop() if(lives > 0) updateWaveSpawning(); updateBloons(); updateTowersAndProjectiles(); draw(); requestAnimationFrame(gameLoop); // ---- EVENT HANDLERS ---- function handleCanvasClick(e) const rect = canvas.getBoundingClientRect(); const scaleX = canvas.width / rect.width; const scaleY = canvas.height / rect.height; let mouseX = (e.clientX - rect.left) * scaleX; let mouseY = (e.clientY - rect.top) * scaleY; mouseX = Math.min(W-15, Math.max(15, mouseX)); mouseY = Math.min(H-15, Math.max(15, mouseY)); tryPlaceTower(mouseX, mouseY); updateUI(); // buy tower button logic document.getElementById('buyTowerBtn').addEventListener('click', () => // manual placement mode is via canvas click, but button just informs if(lives <= 0) return; alert("💰 Click anywhere on the grassy track area to build a DART MONKEY! (150 gold)"); ); document.getElementById('resetGameBtn').addEventListener('click', () => resetGame(); ); canvas.addEventListener('click', handleCanvasClick); // initialize game resetGame(); // also sets wave start after short timeout // start loop gameLoop(); )(); </script> </body> </html> .stat color: #f9e7b3; text-shadow: 0 2px 0 #3a2a1a; font-size: 1.3rem; letter-spacing: 1px; unblocked bloons .stats display: flex; gap: 28px; background: #00000066; padding: 6px 20px; border-radius: 40px; font-weight: bold; <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <title>Unblocked Bloons · Tower Defense Feature</title> <style> * user-select: none; -webkit-tap-highlight-color: transparent; @media (max-width: 760px) <script> (function() // ---------- CANVAS ---------- const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); body background: linear-gradient(145deg, #0a2f2a 0%, #0a1f1a 100%); min-height: 100vh; display: flex; justify-content: center; align-items: center; font-family: 'Segoe UI', 'Courier New', 'Press Start 2P', system-ui, monospace; margin: 0; padding: 20px; ctx.font = "bold 14px 'Segoe UI'" .status background: #000000aa; border-radius: 32px; padding: 5px 18px; font-size: 0.9rem; font-weight: bold; color: #fdd998; |
||
|
+ Pikachu là một nhân vật chính trong phim, nó được coi là một Linh Vật. + Game Pikachu là một game có cách chơi đơn giản, dễ dàng. Game được coi là một trong những Game giải trí, thư giãn, game văn phòng hàng đầu trên PC. + Hiện Game pikachu đã có mặt trên web, máy tính, các dòng điện thoại từ đơn giản như Java, tới các dòng điện thoại thông minh như Android, iPhone. + Game pikachu được rất nhiều nhà sản xuất phát hành với các phong cách, giao diện, khác nhau, cấu trúc bản đồ, biểu tượng, độ khó khác nhau. + Với phần lớn người chơi thích chơi phiên bản đầu tiên Pikachu Cổ Điển như bạn đang nhìn thấy vì đó là bản game đơn giản nhất, hình ảnh gần gũi với cốt chuyện, phim, bố cục rõ ràng không gây đau mắt... + Nếu bạn chơi chưa thành thạo và chiến thằng trong bản Game Pikachu Cổ Điểm, hãy chơi thử bản Tải Game Pikachu Phiên Bản mới đơn giản hơn, hoặc tập luyện với Tải Game pikachu bản tiếng Việt. Bạn hãy đánh dấu Website này lại để chơi bất cứ khi nào trên TaiGamePikachu.VN. |