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>Flappy Bird Mobile</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #111;
color: #fff;
font-family: 'Courier New', Courier, monospace;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
overflow: hidden;
touch-action: manipulation;
}
h1 {
margin: 5px 0;
font-size: 22px;
text-transform: uppercase;
letter-spacing: 2px;
}
#game-container {
position: relative;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.8);
width: 100%;
max-width: 400px;
}
canvas {
background-color: #70c5ce; /* Warna langit khas Flappy Bird */
display: block;
width: 100%;
height: auto;
border: 3px solid #fff;
}
.instructions {
margin-top: 15px;
font-size: 14px;
color: #aaa;
text-align: center;
}
</style>
</head>
<body>
<h1>Flappy Bird</h1>
<div id="game-container">
<canvas id="gameCanvas" width="320" height="480"></canvas>
</div>
<div class="instructions">
Ketuk (Tap) layar untuk membuat burung terbang!
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// Variabel Game
let score = 0;
let gameOver = false;
let gameStarted = false;
// Properti Burung
const bird = {
x: 50,
y: 150,
width: 24,
height: 20,
gravity: 0.5,
lift: -7.5,
velocity: 0
};
// Properti Pipa
let pipes = [];
const pipeWidth = 50;
const pipeGap = 120;
let pipeTimer = 0;
const pipeInterval = 90; // Jarak antar pipa
// Kontrol Sentuh / Klik untuk Melompat
function jump() {
if (gameOver) {
resetGame();
} else {
gameStarted = true;
bird.velocity = bird.lift;
}
}
window.addEventListener('touchstart', (e) => {
e.preventDefault();
jump();
}, { passive: false });
window.addEventListener('mousedown', () => {
jump();
});
window.addEventListener('keydown', (e) => {
if (e.code === 'Space' || e.code === 'ArrowUp') {
jump();
}
});
function resetGame() {
bird.y = 150;
bird.velocity = 0;
pipes = [];
score = 0;
pipeTimer = 0;
gameOver = false;
gameStarted = false;
}
function update() {
if (!gameStarted || gameOver) return;
// Gravitasi Burung
bird.velocity += bird.gravity;
bird.y += bird.velocity;
// Batas Atas & Bawah Layar
if (bird.y + bird.height >= canvas.height - 50) {
bird.y = canvas.height - 50 - bird.height;
gameOver = true;
}
if (bird.y <= 0) {
bird.y = 0;
bird.velocity = 0;
}
// Spawn Pipa
pipeTimer++;
if (pipeTimer >= pipeInterval) {
const minHeight = 50;
const maxHeight = canvas.height - 150 - pipeGap;
const topHeight = Math.floor(Math.random() * (maxHeight - minHeight + 1)) + minHeight;
pipes.push({
x: canvas.width,
top: topHeight,
bottom: canvas.height - 50 - (topHeight + pipeGap),
passed: false
});
pipeTimer = 0;
}
// Pergerakan & Deteksi Tabrakan Pipa
for (let i = pipes.length - 1; i >= 0; i--) {
pipes[i].x -= 2.5; // Kecepatan pipa geser ke kiri
// Cek Skor (Jika burung melewati pipa)
if (!pipes[i].passed && pipes[i].x + pipeWidth < bird.x) {
score++;
pipes[i].passed = true;
}
// Cek Tabrakan (Colission) dengan Pipa Atas atau Bawah
if (
bird.x < pipes[i].x + pipeWidth &&
bird.x + bird.width > pipes[i].x &&
(bird.y < pipes[i].top || bird.y + bird.height > canvas.height - 50 - pipes[i].bottom)
) {
gameOver = true;
}
// Hapus pipa yang sudah keluar layar
if (pipes[i].x + pipeWidth < 0) {
pipes.splice(i, 1);
}
}
}
function draw() {
// Background Langit
ctx.fillStyle = '#70c5ce';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Gambar Pipa
pipes.forEach(pipe => {
ctx.fillStyle = '#73bf2e'; // Hijau pipa klasik
// Pipa Atas
ctx.fillRect(pipe.x, 0, pipeWidth, pipe.top);
ctx.strokeStyle = '#558022';
ctx.lineWidth = 2;
ctx.strokeRect(pipe.x, 0, pipeWidth, pipe.top);
// Pipa Bawah
ctx.fillRect(pipe.x, canvas.height - 50 - pipe.bottom, pipeWidth, pipe.bottom);
ctx.strokeRect(pipe.x, canvas.height - 50 - pipe.bottom, pipeWidth, pipe.bottom);
});
// Gambar Tanah / Rumput Bawah
ctx.fillStyle = '#ded895'; // Tanah
ctx.fillRect(0, canvas.height - 50, canvas.width, 50);
ctx.fillStyle = '#5ee270'; // Rumput atas tanah
ctx.fillRect(0, canvas.height - 50, canvas.width, 12);
// Gambar Burung (Kuning)
ctx.fillStyle = '#f8e71c';
ctx.fillRect(bird.x, bird.y, bird.width, bird.height);
ctx.strokeStyle = '#b8860b';
ctx.strokeRect(bird.x, bird.y, bird.width, bird.height);
// Mata Burung
ctx.fillStyle = '#fff';
ctx.fillRect(bird.x + 14, bird.y + 4, 6, 6);
ctx.fillStyle = '#000';
ctx.fillRect(bird.x + 18, bird.y + 6, 2, 2);
// Paruh Burung
ctx.fillStyle = '#f5a623';
ctx.fillRect(bird.x + bird.width, bird.y + 8, 6, 5);
// UI Skor
ctx.fillStyle = '#fff';
ctx.font = 'bold 32px "Courier New"';
ctx.textAlign = 'center';
ctx.shadowColor = 'rgba(0,0,0,0.5)';
ctx.shadowBlur = 4;
ctx.fillText(score, canvas.width / 2, 60);
ctx.shadowBlur = 0; // Reset shadow
// Pesan Awal / Belum Mulai
if (!gameStarted && !gameOver) {
ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#fff';
ctx.font = 'bold 20px "Courier New"';
ctx.fillText('KETUK UNTUK MULAI', canvas.width / 2, canvas.height / 2);
}
// Layar Game Over
if (gameOver) {
ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ff4d4d';
ctx.font = 'bold 30px "Courier New"';
ctx.fillText('GAME OVER', canvas.width / 2, canvas.height / 2 - 30);
ctx.fillStyle = '#fff';
ctx.font = '18px "Courier New"';
ctx.fillText(`Skor: ${score}`, canvas.width / 2, canvas.height / 2 + 10);
ctx.fillText('Ketuk untuk Main Lagi', canvas.width / 2, canvas.height / 2 + 50);
}
ctx.textAlign = 'left';
}
function loop() {
update();
draw();
requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>
1
1
9KB
9KB
106.0ms
136.0ms
106.0ms