Meta Description" name="description" />
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Zombie Shooter Mobile</title>
<style>
body {
margin: 0;
background-color: #111;
color: white;
font-family: sans-serif;
display: flex;
flex-direction: column;
align-items: center;
touch-action: none; /* Anti-scroll saat main */
user-select: none;
}
#ui {
margin: 10px 0;
font-size: 18px;
font-weight: bold;
}
canvas {
background-color: #222;
border: 2px solid #444;
display: block;
}
#controls {
margin-top: 15px;
display: flex;
gap: 15px;
}
button {
width: 80px;
height: 65px;
font-size: 16px;
font-weight: bold;
border-radius: 12px;
border: none;
background-color: #444;
color: white;
}
#btnTembak { width: 100px; background-color: #d9534f; }
</style>
</head>
<body>
<div id="ui">WAVE: <span id="wave">1</span>/10 | SKOR: <span id="score">0</span></div>
<canvas id="gameCanvas" width="300" height="380"></canvas>
<div id="controls">
<button id="btnKiri">KIRI</button>
<button id="btnTembak">TEMBAK</button>
<button id="btnKanan">KANAN</button>
</div>
<script>
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
// Variabel Karakter
let player = { x: 135, y: 340, w: 30, h: 30, speed: 0 };
let bullets = [];
let zombies = [];
let score = 0;
let wave = 1;
let maxWaves = 10;
let gameOver = false;
let win = false;
let frame = 0;
// Ambil Elemen Tombol
const btnKiri = document.getElementById("btnKiri");
const btnKanan = document.getElementById("btnKanan");
const btnTembak = document.getElementById("btnTembak");
// Fungsi Gerak & Tembak
function jalankanKiri() { player.speed = -5; }
function jalankanKanan() { player.speed = 5; }
function stopGerak() { player.speed = 0; }
function tembakPeluru() {
if(!gameOver && !win) {
bullets.push({ x: player.x + 12, y: player.y, w: 6, h: 12 });
}
}
// Event khusus Touchscreen HP
btnKiri.addEventListener('touchstart', (e) => { e.preventDefault(); jalankanKiri(); });
btnKiri.addEventListener('touchend', (e) => { e.preventDefault(); stopGerak(); });
btnKanan.addEventListener('touchstart', (e) => { e.preventDefault(); jalankanKanan(); });
btnKanan.addEventListener('touchend', (e) => { e.preventDefault(); stopGerak(); });
btnTembak.addEventListener('touchstart', (e) => { e.preventDefault(); tembakPeluru(); });
// Backup untuk Klik Mouse (PC/Laptop)
btnKiri.onmousedown = jalankanKiri; btnKiri.onmouseup = stopGerak;
btnKanan.onmousedown = jalankanKanan; btnKanan.onmouseup = stopGerak;
btnTembak.onmousedown = tembakPeluru;
function spawnZombie() {
let x = Math.random() * (canvas.width - 25);
let speed = 1 + (wave * 0.25);
zombies.push({ x: x, y: -25, w: 25, h: 25, speed: speed });
}
function update() {
if (gameOver || win) return;
player.x += player.speed;
if (player.x < 0) player.x = 0;
if (player.x > canvas.width - player.w) player.x = canvas.width - player.w;
for (let i = bullets.length - 1; i >= 0; i--) {
bullets[i].y -= 6;
if (bullets[i].y < 0) bullets.splice(i, 1);
}
// Atur kemunculan zombie berdasarkan wave
if (frame % Math.max(25, (90 - wave * 6)) === 0) spawnZombie();
for (let i = zombies.length - 1; i >= 0; i--) {
zombies[i].y += zombies[i].speed;
// Cek Kalah (Ditabrak atau zombie lolos ke bawah)
if ((zombies[i].y + zombies[i].h > player.y &&
zombies[i].x < player.x + player.w &&
zombies[i].x + zombies[i].w > player.x) || zombies[i].y > canvas.height) {
gameOver = true;
}
// Cek Kena Tembak
for (let j = bullets.length - 1; j >= 0; j--) {
if (zombies[i] && bullets[j] &&
bullets[j].x < zombies[i].x + zombies[i].w &&
bullets[j].x + bullets[j].w > zombies[i].x &&
bullets[j].y < zombies[i].y + zombies[i].h &&
bullets[j].y + bullets[j].h > zombies[i].y) {
zombies.splice(i, 1);
bullets.splice(j, 1);
score++;
if (score >= wave * 8) {
wave++;
if (wave > maxWaves) win = true;
}
break;
}
}
}
document.getElementById("wave").innerText = wave;
document.getElementById("score").innerText = score;
frame++;
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Gambar Player (Kotak Biru)
ctx.fillStyle = "#3498db";
ctx.fillRect(player.x, player.y, player.w, player.h);
// Gambar Peluru (Kotak Kuning)
ctx.fillStyle = "#f1c40f";
for (let b of bullets) {
ctx.fillRect(b.x, b.y, b.w, b.h);
}
// Gambar Zombie (Kotak Hijau)
ctx.fillStyle = "#2ecc71";
for (let z of zombies) {
ctx.fillRect(z.x, z.y, z.w, z.h);
}
// Teks Akhir Game
ctx.fillStyle = "white";
ctx.font = "bold 24px sans-serif";
if (gameOver) {
ctx.fillStyle = "rgba(0,0,0,0.8)";
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = "#e74c3c";
ctx.fillText("GAME OVER", 75, 180);
} else if (win) {
ctx.fillStyle = "rgba(0,0,0,0.8)";
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = "#f1c40f";
ctx.fillText("KAMU MENANG! π", 50, 180);
}
}
// Jalankan game menggunakan SetInterval agar lebih stabil di webview HP
setInterval(() => {
update();
draw();
}, 1000 / 60); // 60 FPS berkelanjutan
</script>
</body>
</html>1
1
7KB
7KB
143.0ms
164.0ms
144.0ms