SKY HOP
by SuperScout73255 lines5.5 KB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>SKY HOP</title>
<style>
*{box-sizing:border-box}
html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#50b8e8;touch-action:none;font-family:Arial}
canvas{display:block;width:100%;height:100%;touch-action:none}
</style>
</head>
<body>
<canvas id="game"></canvas>
<script>
(()=>{
'use strict';
const canvas=document.getElementById('game');
const ctx=canvas.getContext('2d');
let w=0,h=0,dpr=1,scale=1,ox=0,oy=0;
function resize(){
dpr=Math.min(window.devicePixelRatio||1,2);
w=window.innerWidth;h=window.innerHeight;
canvas.width=Math.floor(w*dpr);
canvas.height=Math.floor(h*dpr);
canvas.style.width=w+'px';
canvas.style.height=h+'px';
scale=Math.min(w/400,h/700);
ox=(w-400*scale)/2;
oy=(h-700*scale)/2;
}
window.addEventListener('resize',resize);
resize();
let mode='ready';
let bird={x:105,y:300,vy:0,rot:0};
let pipes=[],score=0,best=0,spawn=0,last=0,ground=0;
try{best=Number(localStorage.getItem('skyhop_best')||0)||0;}catch(e){}
const gravity=1250,flap=-390,speed=175,gap=175,groundY=625;
function start(){
mode='playing';
bird={x:105,y:300,vy:0,rot:0};
pipes=[];
score=0;
spawn=.65;
}
function jump(){
if(mode==='ready'||mode==='over'){
start();
bird.vy=flap;
return;
}
if(mode==='playing')bird.vy=flap;
}
canvas.addEventListener('pointerdown',e=>{
e.preventDefault();
jump();
});
window.addEventListener('keydown',e=>{
if(e.code==='Space'||e.code==='ArrowUp'){
e.preventDefault();
if(!e.repeat)jump();
}
});
function rect(x,y,w,h,c){
ctx.fillStyle=c;
ctx.fillRect(x,y,w,h);
}
function circle(x,y,r,c){
ctx.fillStyle=c;
ctx.beginPath();
ctx.arc(x,y,r,0,Math.PI*2);
ctx.fill();
}
function text(t,x,y,size,color='#fff'){
ctx.font='bold '+size+'px Arial';
ctx.textAlign='center';
ctx.lineWidth=4;
ctx.strokeStyle='#31536a';
ctx.strokeText(t,x,y);
ctx.fillStyle=color;
ctx.fillText(t,x,y);
}
function cloud(x,y,s){
ctx.save();
ctx.translate(x,y);
ctx.scale(s,s);
circle(0,10,18,'rgba(255,255,255,.9)');
circle(20,0,23,'rgba(255,255,255,.9)');
circle(43,12,17,'rgba(255,255,255,.9)');
rect(0,10,43,19,'rgba(255,255,255,.9)');
ctx.restore();
}
function drawPipe(p){
const x=p.x,top=p.top,bottom=top+gap;
const g=ctx.createLinearGradient(x,0,x+64,0);
g.addColorStop(0,'#218344');
g.addColorStop(.35,'#75e65b');
g.addColorStop(1,'#176d38');
rect(x,0,64,top-22,g);
rect(x-5,top-28,74,28,'#319e45');
rect(x+8,0,7,top-28,'rgba(255,255,255,.22)');
rect(x,bottom+22,64,groundY-bottom-22,g);
rect(x-5,bottom,74,28,'#319e45');
rect(x+8,bottom+28,7,groundY-bottom-50,'rgba(255,255,255,.22)');
}
function drawBird(){
ctx.save();
ctx.translate(bird.x,bird.y);
ctx.rotate(bird.rot);
circle(0,0,17,'#ffc83d');
circle(-4,5,10,'#f4a52b');
circle(9,-7,6,'white');
circle(11,-7,2.8,'#23313b');
ctx.fillStyle='#f17a2d';
ctx.beginPath();
ctx.moveTo(15,0);
ctx.lineTo(30,5);
ctx.lineTo(15,9);
ctx.closePath();
ctx.fill();
ctx.fillStyle='#e9952c';
ctx.beginPath();
ctx.ellipse(-17,0,9,5,-.3,0,Math.PI*2);
ctx.fill();
ctx.restore();
}
function draw(){
ctx.setTransform(dpr,0,0,dpr,0,0);
ctx.clearRect(0,0,w,h);
ctx.save();
ctx.translate(ox,oy);
ctx.scale(scale,scale);
const sky=ctx.createLinearGradient(0,0,0,700);
sky.addColorStop(0,'#50b8e8');
sky.addColorStop(1,'#c4edf1');
rect(0,0,400,700,sky);
circle(330,100,36,'#ffe99b');
cloud(50,125,1);
cloud(250,190,.8);
cloud(430,105,1.1);
ctx.fillStyle='#9ed38d';
ctx.beginPath();
ctx.moveTo(0,500);
for(let x=0;x<=400;x+=10){
ctx.lineTo(x,465+Math.sin((x+ground*.2)/40)*17);
}
ctx.lineTo(400,625);
ctx.lineTo(0,625);
ctx.fill();
for(const p of pipes)drawPipe(p);
rect(0,groundY,400,75,'#d9c17a');
rect(0,groundY,400,14,'#69c64d');
rect(0,groundY+14,400,5,'#439b3a');
for(let x=-(ground%38);x<400;x+=38){
rect(x,groundY+30,20,7,'#b49a5e');
rect(x+12,groundY+52,15,6,'#b49a5e');
}
drawBird();
text(String(score),200,78,48);
ctx.textAlign='left';
ctx.font='bold 14px Arial';
ctx.fillStyle='#fff';
ctx.fillText('BEST '+best,15,25);
if(mode==='ready'||mode==='over'){
rect(32,220,336,250,'rgba(19,48,67,.88)');
text(mode==='ready'?'SKY HOP':'GAME OVER',200,280,34,'#ffe47a');
text(mode==='ready'?'TAP TO FLY':'SCORE: '+score,200,335,23);
text(mode==='ready'?'Avoid the green pipes':'BEST: '+best,200,375,17);
text(mode==='ready'?'SPACE / CLICK':'TAP TO RESTART',200,425,19,'#ffe47a');
}
ctx.restore();
}
function update(dt){
ground+=speed*dt;
if(mode==='playing'){
bird.vy+=gravity*dt;
bird.y+=bird.vy*dt;
bird.rot=Math.max(-.5,Math.min(1,bird.vy/600));
spawn-=dt;
if(spawn<=0){
pipes.push({x:420,top:105+Math.random()*270,passed:false});
spawn=1.55;
}
for(const p of pipes){
p.x-=speed*dt;
if(!p.passed&&p.x+64<bird.x){
p.passed=true;
score++;
if(score>best){
best=score;
try{localStorage.setItem('skyhop_best',String(best));}catch(e){}
}
}
if(bird.x+13>p.x&&bird.x-13<p.x+64&&
(bird.y-13<p.top||bird.y+13>p.top+gap)){
mode='over';
}
}
pipes=pipes.filter(p=>p.x>-90);
if(bird.y+14>=groundY||bird.y-14<0){
mode='over';
}
}else if(mode==='over'&&bird.y+14<groundY){
bird.vy+=gravity*dt;
bird.y+=bird.vy*dt;
bird.rot=Math.min(1.2,bird.rot+dt*2);
}
}
function loop(t){
const dt=Math.min((t-last)/1000||0,.033);
last=t;
update(dt);
draw();
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
})();
</script>
</body>
</html>
Game Source: SKY HOP
Creator: SuperScout73
Libraries: none
Complexity: complex (255 lines, 5.5 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: sky-hop-superscout73" to link back to the original. Then publish at arcadelab.ai/publish.