0% found this document useful (0 votes)
27 views9 pages

Flappy Bird Game in Single HTML File

Uploaded by

mstbarna1990
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
27 views9 pages

Flappy Bird Game in Single HTML File

Uploaded by

mstbarna1990
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

<!

doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Flappy Bird — Single File</title>
<style>
:root{
--bg:#70c5ce;
--ground:#dcae6b;
--pipe:#2e8b57;
--bird:#ffdd57;
--text:#ffffff;
}
html,body{height:100%;margin:0;font-family:Inter,system-ui,Arial,sans-
serif;background:var(--bg);}
.wrap{
display:flex;align-items:center;justify-
content:center;height:100vh;padding:20px;
box-sizing:border-box;
}
canvas{
background: linear-gradient(#70c5ce 0%, #81d0dd 60%);
border-radius:12px;
box-shadow: 0 8px 30px rgba(15,40,60,.25);
display:block;
max-width:100%;
height:auto;
}
.ui{
position: absolute;
top:18px; left:50%; transform:translateX(-50%);
display:flex; gap:12px; align-items:center;
pointer-events:none;
}
.badge{
background:rgba(0,0,0,0.25); color:var(--text); padding:8px 12px; border-
radius:999px;
font-weight:600; font-size:14px; backdrop-filter: blur(4px);
pointer-events:auto;
}
.controls{
position: absolute; bottom:24px; left:50%; transform:translateX(-50%);
display:flex; gap:10px;
pointer-events:auto;
}
button{
padding:8px 12px;border-radius:10px;border:0;background:#fff;color:#222;font-
weight:600;cursor:pointer;
box-shadow:0 6px 18px rgba(10,20,30,.15);
}
.overlay{
position:absolute; inset:0; display:flex; align-items:center; justify-
content:center; pointer-events:none;
}
.panel{
background:rgba(255,255,255,0.98); padding:18px 22px; border-radius:12px; text-
align:center;
box-shadow:0 8px 30px rgba(10,20,30,.12); pointer-events:auto; max-width:90%;
}
[Link]{color:#1a73e8;text-decoration:none;font-weight:600;}
small{display:block;color:#666;margin-top:8px}
@media (max-width:420px){
.badge{font-size:13px;padding:6px 10px}
button{padding:8px 10px}
}
</style>
</head>
<body>
<div class="wrap">
<canvas id="game" width="480" height="640" aria-label="Flappy Bird
game"></canvas>

<div class="ui" id="hud">


<div class="badge" id="score">SCORE: 0</div>
<div class="badge" id="best">BEST: 0</div>
</div>

<div class="controls" id="controls" style="display:none;">


<button id="btnRestart">Restart</button>
<button id="btnMute">Mute</button>
</div>

<div class="overlay" id="startOverlay">


<div class="panel" id="panelStart">
<h2 style="margin:0">Flappy Bird — Single File</h2>
<p style="margin:10px 0 0">Press <strong>Space</strong> or tap/click to flap.
Avoid pipes. Good luck!</p>
<small>Tip: press and hold to keep fluttering a few times rapidly.</small>
<div style="margin-top:12px">
<button id="startBtn">Start</button>
<a class="inline" href="#" id="showHelp" style="margin-left:10px">Help</a>
</div>
</div>
</div>

</div>

<script>
/* --------- Flappy Bird single-file implementation ---------
Controls: Space / ArrowUp / Click / Touch => flap
Features:
- Responsive canvas scaling
- Real physics-ish feel (gravity, flap impulse)
- Randomized pipe gaps, increasing difficulty over time
- Score + best stored in localStorage
- Pause / restart / mute
-----------------------------------------------------------*/

(() => {
const canvas = [Link]('game');
const ctx = [Link]('2d');

// UI
const scoreEl = [Link]('score');
const bestEl = [Link]('best');
const startOverlay = [Link]('startOverlay');
const startBtn = [Link]('startBtn');
const controls = [Link]('controls');
const btnRestart = [Link]('btnRestart');
const btnMute = [Link]('btnMute');

// state
let W = [Link], H = [Link];
let scaleCanvas = 1;
let lastTime = 0;
let running = false;
let muted = false;

// Game constants
const GRAVITY = 900; // px/s^2
const FLAP_V = -300; // px/s impulse
const PIPE_W = 80;
const PIPE_GAP_MIN = 150;
const PIPE_GAP_MAX = 210;
const PIPE_SPACING = 220; // distance between pipes
const GROUND_HEIGHT = 80;

// Bird
const bird = {
x: W * 0.28,
y: H * 0.4,
w: 36,
h: 26,
vy: 0,
rot: 0,
alive: true
};

// Pipes container
let pipes = [];
let scrollX = 0;
let pipeTimer = 0;
let score = 0;
let best = parseInt([Link]('flappy_best') || '0', 10);

[Link] = 'BEST: ' + best;

// Sounds (simple oscillator-based beeps)


function beep(freq, time=0.08, type='sine'){
if(muted) return;
try {
const ctxA = new ([Link] || [Link])();
const o = [Link]();
const g = [Link]();
[Link] = type;
[Link] = freq;
[Link] = 0.0025 * 60; // moderate level
[Link](g);
[Link]([Link]);
[Link]();
[Link](0.0001, [Link] + time);
setTimeout(()=>{ [Link](); [Link](); }, [Link](150, time*1000 + 20));
} catch(e){}
}

// Resize handling: keep aspect ratio, scale canvas visually


function resizeToFit(){
const containerW = [Link]([Link] - 40, 480);
const containerH = [Link]([Link] - 80, 800);
// scale preserving canvas aspect ratio
scaleCanvas = [Link](containerW / W, containerH / H);
[Link] = [Link](W * scaleCanvas) + 'px';
[Link] = [Link](H * scaleCanvas) + 'px';
}
[Link]('resize', resizeToFit);
resizeToFit();

// Utility random
function rand(a,b){ return [Link]()*(b-a)+a; }

// Start / reset
function resetGame(){
bird.x = W * 0.28;
bird.y = H * 0.4;
[Link] = 0;
[Link] = 0;
[Link] = true;
pipes = [];
scrollX = 0;
pipeTimer = 0;
score = 0;
updateScoreUI();
}

function startGame(){
resetGame();
running = true;
[Link] = 'none';
[Link] = 'flex';
lastTime = [Link]();
beep(880,0.06,'square');
requestAnimationFrame(loop);
}

// Input handlers
function flap(){
if(![Link]) return;
[Link] = FLAP_V;
// little rotation upwards
[Link] = -0.5;
beep(700,0.06,'sine');
}

[Link]('keydown', (e)=>{
if([Link] === 'Space' || [Link] === 'ArrowUp') {
[Link]();
if(!running){ startGame(); return; }
flap();
} else if([Link] === 'KeyM'){
toggleMute();
}
});

[Link]('mousedown', (e)=>{
if(!running){ startGame(); return; }
flap();
});
[Link]('touchstart', (e)=>{
[Link]();
if(!running){ startGame(); return; }
flap();
}, {passive:false});

[Link]('click', startGame);
[Link]('click', ()=>{
[Link] = 'none';
resetGame();
running = true;
lastTime = [Link]();
requestAnimationFrame(loop);
});

[Link]('click', toggleMute);

function toggleMute(){
muted = !muted;
[Link] = muted ? 'Unmute' : 'Mute';
}

// Pipe generation
function spawnPipe(){
const gap = rand(PIPE_GAP_MIN, PIPE_GAP_MAX);
const yTop = rand(40, H - GROUND_HEIGHT - 40 - gap);
const pipe = {
x: W + 20,
topY: 0,
topH: yTop,
bottomY: yTop + gap,
bottomH: H - GROUND_HEIGHT - (yTop + gap),
passed: false
};
[Link](pipe);
}

// Collision detection (AABB)


function rectsOverlap(ax,ay,aw,ah, bx,by,bw,bh){
return ax < bx + bw && ax + aw > bx && ay < by + bh && ay + ah > by;
}

// Update score UI
function updateScoreUI(){
[Link] = 'SCORE: ' + [Link](0, [Link](score));
[Link] = 'BEST: ' + best;
}

// Game loop
function loop(now){
if(!running) return;
const dt = [Link]((now - lastTime) / 1000, 0.035); // seconds; clamp
lastTime = now;

// physics
[Link] += GRAVITY * dt;
bird.y += [Link] * dt;
// rotation approach toward falling angle
[Link] += ([Link](1.2, [Link] / 300) - [Link]) * 6 * dt;

// scroll speed increases slowly with score


const baseSpeed = 120 + [Link](180, [Link](score)*3);
scrollX += baseSpeed * dt;

// spawn pipes periodically


pipeTimer += baseSpeed * dt;
if(pipeTimer > PIPE_SPACING){
pipeTimer = 0;
spawnPipe();
}

// move pipes
for(let i = [Link] -1; i >= 0; --i){
const p = pipes[i];
p.x -= baseSpeed * dt;
// scoring: when pipe center passes bird.x and not counted yet
if(![Link] && p.x + PIPE_W/2 < bird.x){
[Link] = true;
score += 1;
beep(900,0.05,'triangle');
if([Link](score) > best){
best = [Link](score);
[Link]('flappy_best', String(best));
}
}
// remove off-screen
if(p.x + PIPE_W < -50) [Link](i,1);
}

// collision with ground or ceiling


if(bird.y + bird.h/2 >= H - GROUND_HEIGHT){
bird.y = H - GROUND_HEIGHT - bird.h/2;
[Link] = false;
running = false;
endGame();
}
if(bird.y - bird.h/2 <= 0){
bird.y = bird.h/2;
[Link] = 0;
}

// collisions with pipes


for(const p of pipes){
// top pipe rect
if(rectsOverlap(bird.x - bird.w/2, bird.y - bird.h/2, bird.w, bird.h,
p.x, [Link], PIPE_W, [Link]) ||
rectsOverlap(bird.x - bird.w/2, bird.y - bird.h/2, bird.w, bird.h,
p.x, [Link], PIPE_W, [Link])){
[Link] = false;
running = false;
beep(120,0.25,'sawtooth');
endGame();
break;
}
}
// render
render();

if(running) requestAnimationFrame(loop);
}

// End game UI
function endGame(){
updateScoreUI();
// show overlay with stats
const panel = [Link]('panelStart');
[Link] = `<h2 style="margin:0">Game Over</h2>
<p style="margin:10px 0 0">Score: <strong>${[Link](0,
[Link](score))}</strong></p>
<p style="margin:6px 0 0">Best: <strong>${best}</strong></p>
<div style="margin-top:10px">
<button id="playAgain">Play Again</button>
<button id="toMenu" style="margin-left:8px">Menu</button>
</div>
<small style="margin-top:8px;display:block;color:#666">Space / Tap to flap —
Avoid the pipes</small>`;
[Link] = 'flex';
[Link] = 'flex';
// wire up the new buttons
setTimeout(()=>{
const playAgain = [Link]('playAgain');
const toMenu = [Link]('toMenu');
playAgain && [Link]('click', ()=>{
[Link]='none';
resetGame();
running = true;
lastTime = [Link]();
requestAnimationFrame(loop);
});
toMenu && [Link]('click', ()=>{
// restore original start panel
[Link] = `<h2 style="margin:0">Flappy Bird — Single File</h2>
<p style="margin:10px 0 0">Press <strong>Space</strong> or tap/click to
flap. Avoid pipes. Good luck!</p>
<small>Tip: press and hold to keep fluttering a few times rapidly.</small>
<div style="margin-top:12px">
<button id="startBtn">Start</button>
<a class="inline" href="#" id="showHelp"
style="margin-left:10px">Help</a>
</div>`;
[Link]='flex';
// reattach start button
setTimeout(()=>{
const startBtnNew = [Link]('startBtn');
startBtnNew && [Link]('click', startGame);
}, 0);
});
}, 20);
}

// Drawing
function drawRoundedRect(x,y,w,h,r){
[Link]();
[Link](x+r, y);
[Link](x+w, y, x+w, y+h, r);
[Link](x+w, y+h, x, y+h, r);
[Link](x, y+h, x, y, r);
[Link](x, y, x+w, y, r);
[Link]();
[Link]();
}

function render(){
// clear
[Link](0,0,W,H);

// sky - subtle gradient already via CSS; we'll draw background elements
// sun
[Link]();
[Link] = 0.12;
[Link]();
[Link] = '#fff5b1';
[Link](W - 90, 80, 50, 0, [Link]*2);
[Link]();
[Link]();

// draw pipes
for(const p of pipes){
// top pipe
[Link] = '#2e8b57';
drawRoundedRect(p.x, [Link] - 6, PIPE_W, [Link] + 6, 6);
// bottom pipe
drawRoundedRect(p.x, [Link], PIPE_W, [Link] + 6, 6);
// pipe rim
[Link] = '#1e5e3f';
[Link](p.x-2, [Link] - 6, PIPE_W+4, 6);
[Link](p.x-2, [Link], PIPE_W+4, 6);
}

// ground
[Link] = '#dcae6b';
[Link](0, H - GROUND_HEIGHT, W, GROUND_HEIGHT);
// ground detail stripes
[Link] = 'rgba(0,0,0,0.04)';
for(let i=0;i<20;i++){
[Link]((i*40 - (scrollX%40)), H - GROUND_HEIGHT, 20, 6);
}

// bird (simple circle + wing)


[Link]();
[Link](bird.x, bird.y);
[Link]([Link]);
// body
[Link] = '#ffdd57';
[Link]();
[Link](0, 0, bird.w/2, bird.h/2, 0, 0, [Link]*2);
[Link]();
// eye
[Link] = '#333';
[Link]();
[Link](bird.w*0.12, -bird.h*0.06, 3, 0, [Link]*2);
[Link]();
// beak
[Link] = '#ff8a00';
[Link]();
[Link](bird.w*0.35, 0);
[Link](bird.w*0.55, -6);
[Link](bird.w*0.55, 6);
[Link]();
[Link]();
// wing (animated slightly by vy)
[Link]();
const wingTilt = [Link](-0.8, [Link](0.8, -[Link]/300));
[Link](wingTilt);
[Link] = '#f0c94d';
[Link]();
[Link](-4, 6, 10, 5, 0, 0, [Link]*2);
[Link]();
[Link]();
[Link]();

// HUD (score big)


[Link] = 'rgba(0,0,0,0.12)';
[Link] = '700 42px system-ui, Arial';
[Link] = 'center';
[Link]([Link](0, [Link](score)), W/2 + 2, 80 + 2);
[Link] = '#fff';
[Link]([Link](0, [Link](score)), W/2, 80);

// small best
[Link] = '600 14px system-ui, Arial';
[Link] = 'left';
[Link] = 'rgba(0,0,0,0.18)';
[Link]('BEST ' + best, 18 + 2, 34 + 2);
[Link] = '#fff';
[Link]('BEST ' + best, 18, 34);
}

// initial spawn to avoid empty start


spawnPipe();
spawnPipe();

// expose for debug (optional)


window._flappy = {
reset: resetGame,
spawn: spawnPipe,
getState: ()=>({score,best,pipesLength: [Link]})
};

// show initial start overlay and attach start button


[Link] = 'flex';
startBtn && [Link]('click', startGame);

// initial draw
render();
})();
</script>
</body>
</html>

You might also like