Meta Description" name="description" />

Share this result

Previews are deleted daily. Get a permanent share link sent to your inbox:
Script
<!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Boo Shots Game</title> <style> body { margin: 0; background-color: #1a1a1a; color: white; font-family: 'Courier New', Courier, monospace; display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; user-select: none; } #gameContainer { position: relative; width: 100%; max-width: 450px; height: 100%; max-height: 800px; background: #111; border: 4px solid #fff; box-sizing: border-box; } canvas { width: 100%; height: 100%; display: block; } #overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.85); display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; z-index: 10; } button { background: #fff; color: #000; border: none; padding: 15px 30px; font-size: 1.2rem; font-weight: bold; cursor: pointer; margin-top: 20px; font-family: inherit; } button:hover { background: #ccc; } </style> </head> <body> <div id="gameContainer"> <canvas id="gameCanvas"></canvas> <div id="overlay"> <h1 id="titleText">BOO SHOTS</h1> <p id="descText">Tembak hantu sebelum mereka mencapai kotaknya!</p> <button id="startBtn" onclick="startGame()">MAIN</button> </div> </div> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const overlay = document.getElementById('overlay'); const startBtn = document.getElementById('startBtn'); const titleText = document.getElementById('titleText'); const descText = document.getElementById('descText'); // Set resolusi internal canvas canvas.width = 450; canvas.height = 800; // Konfigurasi Game (Sesuai sketsa) const LANES = 5; const laneWidth = canvas.width / LANES; const bottomBlockY = canvas.height - 100; // Posisi blok bawah const blockHeight = 80; let playerLane = 2; // Mulai dari tengah (0, 1, 2, 3, 4) let lives = 5; let score = 0; let ghosts = []; let bullets = []; let gameActive = false; let spawnRate = 1500; // ms let lastSpawn = 0; let ghostSpeed = 2; // Input Handler (Keyboard) window.addEventListener('keydown', (e) => { if (!gameActive) return; if (e.key === 'ArrowLeft' && playerLane > 0) { playerLane--; } else if (e.key === 'ArrowRight' && playerLane < LANES - 1) { playerLane++; } else if (e.key === ' ' || e.key === 'Spacebar') { shoot(); } }); // Input Handler (Touch/Mouse untuk Mobile sesuai sketsa) canvas.addEventListener('click', (e) => { if (!gameActive) return; const rect = canvas.getBoundingClientRect(); const clickX = ((e.clientX - rect.left) / rect.width) * canvas.width; const clickY = ((e.clientY - rect.top) / rect.height) * canvas.height; // Jika klik di area bawah (zona blok player) if (clickY > bottomBlockY - 20) { const clickedLane = Math.floor(clickX / laneWidth); if (clickedLane >= 0 && clickedLane < LANES) { playerLane = clickedLane; shoot(); // Pindah langsung tembak } } }); function shoot() { bullets.push({ x: playerLane * laneWidth + laneWidth / 2, y: bottomBlockY, speed: 8 }); } function spawnGhost() { const randomLane = Math.floor(Math.random() * LANES); // 2 tipe hantu (tengkorak dan hantu biasa seperti di gambar) const type = Math.random() > 0.5 ? 'skull' : 'ghost'; ghosts.push({ lane: randomLane, x: randomLane * laneWidth + laneWidth / 2, y: 50, type: type, radius: 20 }); } function startGame() { lives = 5; score = 0; ghosts = []; bullets = []; ghostSpeed = 2; spawnRate = 1500; gameActive = true; overlay.style.display = 'none'; lastSpawn = Date.now(); animate(); } function gameOver() { gameActive = false; overlay.style.display = 'flex'; titleText.innerText = "GAME OVER"; descText.innerText = `Kamu berhasil menembak ${score} hantu!`; startBtn.innerText = "MAIN LAGI"; } // Menggambar Hantu Bergaya Sketsa function drawGhost(ctx, x, y, type) { ctx.strokeStyle = '#fff'; ctx.lineWidth = 3; ctx.fillStyle = '#111'; if (type === 'ghost') { // Hantu Klasik Klasik ctx.beginPath(); ctx.arc(x, y, 20, Math.PI, 0, false); ctx.lineTo(x + 20, y + 25); // Gerigi bawah ctx.lineTo(x + 10, y + 15); ctx.lineTo(x, y + 25); ctx.lineTo(x - 10, y + 15); ctx.lineTo(x - 20, y + 25); ctx.closePath(); ctx.fill(); ctx.stroke(); // Mata ctx.fillStyle = '#fff'; ctx.beginPath(); ctx.arc(x - 7, y - 2, 4, 0, Math.PI * 2); ctx.arc(x + 7, y - 2, 4, 0, Math.PI * 2); ctx.fill(); } else { // Hantu Tengkorak ctx.beginPath(); ctx.arc(x, y - 5, 22, Math.PI * 1.2, Math.PI * 1.8, false); ctx.lineTo(x + 12, y + 15); ctx.lineTo(x - 12, y + 15); ctx.closePath(); ctx.fill(); ctx.stroke(); // Mata Tengkorak (Hitam/Kosong) ctx.fillStyle = '#fff'; ctx.beginPath(); ctx.arc(x - 8, y - 3, 6, 0, Math.PI * 2); ctx.arc(x + 8, y - 3, 6, 0, Math.PI * 2); ctx.fill(); // Hidung ctx.beginPath(); ctx.moveTo(x, y + 3); ctx.lineTo(x - 3, y + 8); ctx.lineTo(x + 3, y + 8); ctx.closePath(); ctx.fill(); } } function animate() { if (!gameActive) return; ctx.clearRect(0, 0, canvas.width, canvas.height); // 1. Gambar Jalur/Lintasan dan Kotak Atas & Bawah ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)'; ctx.lineWidth = 2; for (let i = 0; i <= LANES; i++) { ctx.beginPath(); ctx.moveTo(i * laneWidth, 0); ctx.lineTo(i * laneWidth, canvas.height); ctx.stroke(); } // Gambar Blok Kotak Atas dan Bawah (Sesuai Sketsa) for (let i = 0; i < LANES; i++) { ctx.strokeStyle = '#fff'; ctx.lineWidth = 3; // Kotak Atas ctx.strokeRect(i * laneWidth + 5, 10, laneWidth - 10, blockHeight); // Kotak Bawah ctx.strokeRect(i * laneWidth + 5, bottomBlockY + 10, laneWidth - 10, blockHeight); } // 2. Spawn Hantu otomatis let now = Date.now(); if (now - lastSpawn > spawnRate) { spawnGhost(); lastSpawn = now; // Tingkatkan kesulitan perlahan if (spawnRate > 600) spawnRate -= 20; ghostSpeed += 0.05; } // 3. Update & Gambar Peluru ctx.fillStyle = '#ff3333'; for (let i = bullets.length - 1; i >= 0; i--) { bullets[i].y -= bullets[i].speed; ctx.beginPath(); ctx.arc(bullets[i].x, bullets[i].y, 6, 0, Math.PI * 2); ctx.fill(); // Hapus peluru keluar layar if (bullets[i].y < 0) bullets.splice(i, 1); } // 4. Update & Gambar Hantu for (let i = ghosts.length - 1; i >= 0; i--) { ghosts[i].y += ghostSpeed; drawGhost(ctx, ghosts[i].x, ghosts[i].y, ghosts[i].type); // Cek jika hantu masuk ke kotak bawah (Lose kondisi di sketsa) if (ghosts[i].y >= bottomBlockY + 10) { ghosts.splice(i, 1); lives--; if (lives <= 0) { gameOver(); return; } continue; } // Cek tabrakan dengan peluru for (let j = bullets.length - 1; j >= 0; j--) { // Cek jalurnya sama dan jarak vertikal dekat let distX = Math.abs(bullets[j].x - ghosts[i].x); let distY = Math.abs(bullets[j].y - ghosts[i].y); if (distX < laneWidth / 2 && distY < 25) { ghosts.splice(i, 1); bullets.splice(j, 1); score += 10; break; } } } // 5. Gambar Karakter Player (Sesuai ikon tangan/pusaran di sketsa) const pX = playerLane * laneWidth + laneWidth / 2; const pY = bottomBlockY + 50; // Menggambar simbol pusaran/penembak ctx.strokeStyle = '#00ffff'; ctx.lineWidth = 4; ctx.beginPath(); ctx.arc(pX, pY, 20, 0, Math.PI * 2); ctx.stroke(); // Moncong tembakan ke atas ctx.fillStyle = '#00ffff'; ctx.fillRect(pX - 5, pY - 30, 10, 15); // 6. Tampilkan Score dan Nyawa (UI) ctx.fillStyle = '#fff'; ctx.font = '20px "Courier New"'; ctx.fillText(`SKOR: ${score}`, 20, 120); // Gambar Jantung/Nyawa (HAVE 5 LIFE di sketsa) let hearts = ""; for(let h=0; h<lives; h++) hearts += "♥ "; ctx.fillStyle = '#ff3366'; ctx.fillText(`NYAWA: ${hearts}`, 20, 150); requestAnimationFrame(animate); } </script> </body> </html>
Landing Page
This ad does not have a landing page available
Network Timeline
Performance Summary

1

Requests

1

Domains

10KB

Transfer Size

10KB

Content Size

130.0ms

Dom Content Loaded

184.0ms

First Paint

130.0ms

Load Time
Domain Breakdown
Transfer Size (bytes)
Loading...
Content Size (bytes)
Loading...
Header Size (bytes)
Loading...
Requests
Loading...
Timings (ms)
Loading...
Total Time
Loading...
Content Breakdown
Transfer Size (bytes)
Loading...
Content Size (bytes)
Loading...
Header Size (bytes)
Loading...
Requests
Loading...