Sky Pilot X
by CrystalTiger192495 lines30.7 KB
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Sky Pilot X</title>
<style>
*{
margin:0;
padding:0;
box-sizing:border-box;
}
html,body{
width:100%;
height:100%;
overflow:hidden;
background:#061b35;
font-family:Arial,sans-serif;
}
canvas{
width:100%;
height:100%;
display:block;
touch-action:none;
}
</style>
</head>
<body>
<canvas id="game"></canvas>
<script>
/* =========================================================
SKY PILOT X
INTRO + LOADING + MENU + GAME
========================================================= */
const canvas=document.getElementById("game");
const ctx=canvas.getContext("2d");
let W=innerWidth;
let H=innerHeight;
let DPR=devicePixelRatio||1;
function resize(){
W=innerWidth;
H=innerHeight;
DPR=devicePixelRatio||1;
canvas.width=W*DPR;
canvas.height=H*DPR;
ctx.setTransform(DPR,0,0,DPR,0,0);
}
resize();
addEventListener("resize",resize);
/* =========================================================
SCREEN STATES
========================================================= */
let screen="unity";
let loading=0;
let menuAlpha=0;
let gameStarted=false;
let crashed=false;
/* =========================================================
GAME VARIABLES
========================================================= */
let score=0;
let best=
Number(localStorage.getItem("skyPilotBest")||0);
let speed=3.2;
let difficulty=0;
let frame=0;
let obstacles=[];
let particles=[];
let clouds=[];
let stars=[];
let shake=0;
/* =========================================================
AIRPLANE
========================================================= */
const plane={
x:0,
y:0,
vx:0,
vy:0,
width:68,
height:38,
angle:0
};
function resetPlane(){
plane.x=W*.23;
plane.y=H*.45;
plane.vx=0;
plane.vy=0;
plane.angle=0;
}
/* =========================================================
CLOUDS
========================================================= */
function makeCloud(x){
clouds.push({
x:x,
y:
40+
Math.random()*H*.38,
size:
.55+
Math.random()*.9,
speed:
.2+
Math.random()*.45
});
}
for(let i=0;i<10;i++){
makeCloud(
Math.random()*W
);
}
/* =========================================================
STARS
========================================================= */
for(let i=0;i<90;i++){
stars.push({
x:Math.random()*W,
y:Math.random()*H*.7,
size:
Math.random()*2,
alpha:
.3+
Math.random()*.7
});
}
/* =========================================================
UNITY OPENING
========================================================= */
function updateUnity(){
if(screen!=="unity")
return;
loading+=0.7;
if(loading>=100){
loading=100;
setTimeout(()=>{
screen="loading";
loading=0;
},500);
}
}
/* =========================================================
LOADING
========================================================= */
function updateLoading(){
if(screen!=="loading")
return;
loading+=1.4;
if(loading>=100){
loading=100;
setTimeout(()=>{
screen="menu";
},400);
}
}
/* =========================================================
DRAW BEAUTIFUL BACKGROUND
========================================================= */
function drawBeautifulBackground(){
const g=
ctx.createLinearGradient(
0,
0,
0,
H
);
g.addColorStop(
0,
"#071b3d"
);
g.addColorStop(
.35,
"#124d83"
);
g.addColorStop(
.68,
"#2ba9d5"
);
g.addColorStop(
1,
"#ffd27a"
);
ctx.fillStyle=g;
ctx.fillRect(
0,
0,
W,
H
);
/* Stars */
for(const s of stars){
ctx.globalAlpha=
s.alpha*
(
.65+
Math.sin(frame*.03+s.x)*.35
);
ctx.fillStyle="#fff";
ctx.beginPath();
ctx.arc(
s.x,
s.y,
s.size,
0,
Math.PI*2
);
ctx.fill();
}
ctx.globalAlpha=1;
/* Moon */
ctx.fillStyle=
"rgba(255,245,190,.95)";
ctx.beginPath();
ctx.arc(
W*.82,
H*.18,
42,
0,
Math.PI*2
);
ctx.fill();
/* Moon shadow */
ctx.fillStyle=
"#124d83";
ctx.beginPath();
ctx.arc(
W*.85,
H*.15,
42,
0,
Math.PI*2
);
ctx.fill();
/* Sun glow */
const glow=
ctx.createRadialGradient(
W*.2,
H*.62,
5,
W*.2,
H*.62,
170
);
glow.addColorStop(
0,
"rgba(255,220,120,.65)"
);
glow.addColorStop(
1,
"rgba(255,220,120,0)"
);
ctx.fillStyle=glow;
ctx.fillRect(
0,
0,
W,
H
);
/* Mountains */
ctx.fillStyle=
"rgba(20,55,75,.65)";
ctx.beginPath();
ctx.moveTo(0,H*.73);
for(
let x=0;
x<=W;
x+=80
){
const y=
H*.63+
Math.sin(x*.012)*50+
Math.sin(x*.027)*25;
ctx.lineTo(
x,
y
);
}
ctx.lineTo(W,H);
ctx.lineTo(0,H);
ctx.closePath();
ctx.fill();
/* City silhouette */
const ground=H*.82;
for(
let x=0;
x<W;
x+=45
){
const bh=
40+
((x*17)%100);
ctx.fillStyle=
"rgba(7,30,45,.85)";
ctx.fillRect(
x,
ground-bh,
38,
bh
);
/* Windows */
ctx.fillStyle=
"rgba(255,213,91,.7)";
for(
let y=
ground-bh+15;
y<
ground-8;
y+=20
){
ctx.fillRect(
x+8,
y,
5,
7
);
ctx.fillRect(
x+23,
y,
5,
7
);
}
}
/* Ground */
ctx.fillStyle="#081b29";
ctx.fillRect(
0,
ground,
W,
H-ground
);
/* Animated horizon */
ctx.fillStyle=
"rgba(255,190,80,.12)";
ctx.fillRect(
0,
ground,
W,
5
);
}
/* =========================================================
DRAW CLOUDS
========================================================= */
function drawCloud(c){
ctx.save();
ctx.translate(
c.x,
c.y
);
ctx.scale(
c.size,
c.size
);
ctx.fillStyle=
"rgba(255,255,255,.16)";
ctx.beginPath();
ctx.arc(
-35,
8,
24,
0,
Math.PI*2
);
ctx.arc(
0,
-7,
33,
0,
Math.PI*2
);
ctx.arc(
35,
8,
24,
0,
Math.PI*2
);
ctx.fill();
ctx.restore();
}
/* =========================================================
INTRO SCREEN
========================================================= */
function drawUnityScreen(){
drawBeautifulBackground();
for(const c of clouds){
c.x-=c.speed*.15;
if(c.x<-180)
c.x=W+100;
drawCloud(c);
}
ctx.textAlign="center";
/* Unity-style title */
ctx.shadowColor=
"rgba(0,0,0,.5)";
ctx.shadowBlur=20;
ctx.fillStyle="#fff";
ctx.font=
"900 46px Arial";
ctx.fillText(
"UNITY",
W/2,
H*.43
);
ctx.shadowBlur=0;
ctx.fillStyle=
"rgba(255,255,255,.75)";
ctx.font=
"14px Arial";
ctx.fillText(
"POWERED BY UNITY",
W/2,
H*.48
);
/* Loading line */
ctx.fillStyle=
"rgba(255,255,255,.2)";
ctx.fillRect(
W*.25,
H*.82,
W*.5,
5
);
ctx.fillStyle="#fff";
ctx.fillRect(
W*.25,
H*.82,
W*.5*(loading/100),
5
);
ctx.textAlign="left";
}
/* =========================================================
LOADING SCREEN
========================================================= */
function drawLoadingScreen(){
drawBeautifulBackground();
for(const c of clouds){
c.x-=c.speed*.25;
if(c.x<-180)
c.x=W+100;
drawCloud(c);
}
ctx.textAlign="center";
ctx.fillStyle="#fff";
ctx.font=
"900 42px Arial";
ctx.fillText(
"SKY PILOT X",
W/2,
H*.38
);
ctx.font=
"bold 17px Arial";
ctx.fillStyle=
"rgba(255,255,255,.8)";
ctx.fillText(
"PREPARING FLIGHT...",
W/2,
H*.46
);
/* Loading box */
const barW=
Math.min(
420,
W*.65
);
const barX=
W/2-barW/2;
ctx.fillStyle=
"rgba(255,255,255,.2)";
ctx.beginPath();
ctx.roundRect(
barX,
H*.54,
barW,
14,
7
);
ctx.fill();
ctx.fillStyle="#fff";
ctx.beginPath();
ctx.roundRect(
barX,
H*.54,
barW*(loading/100),
14,
7
);
ctx.fill();
ctx.font=
"bold 14px Arial";
ctx.fillStyle="#fff";
ctx.fillText(
Math.floor(loading)+"%",
W/2,
H*.60
);
ctx.textAlign="left";
}
/* =========================================================
MENU
========================================================= */
function drawMenu(){
drawBeautifulBackground();
for(const c of clouds){
c.x-=c.speed*.35;
if(c.x<-180)
c.x=W+100;
drawCloud(c);
}
/* Dark overlay */
const overlay=
ctx.createLinearGradient(
0,
0,
0,
H
);
overlay.addColorStop(
0,
"rgba(0,0,0,.15)"
);
overlay.addColorStop(
1,
"rgba(0,0,0,.5)"
);
ctx.fillStyle=overlay;
ctx.fillRect(
0,
0,
W,
H
);
ctx.textAlign="center";
/* Game title */
ctx.shadowColor=
"rgba(0,0,0,.55)";
ctx.shadowBlur=18;
ctx.fillStyle="#fff";
ctx.font=
"900 clamp(42px,10vw,75px) Arial";
ctx.fillText(
"SKY PILOT",
W/2,
H*.25
);
ctx.fillStyle="#ffd34d";
ctx.font=
"900 clamp(18px,4vw,30px) Arial";
ctx.fillText(
"X",
W/2,
H*.31
);
ctx.shadowBlur=0;
/* Subtitle */
ctx.fillStyle=
"rgba(255,255,255,.85)";
ctx.font=
"16px Arial";
ctx.fillText(
"FLY • DODGE • SURVIVE",
W/2,
H*.37
);
/* =================================================
START BUTTON
================================================= */
const buttonW=
Math.min(
230,
W*.48
);
const buttonH=68;
const buttonY=
H*.56;
/* Button shadow */
ctx.fillStyle=
"rgba(0,0,0,.35)";
ctx.beginPath();
ctx.roundRect(
W/2-
buttonW/2+
4,
buttonY+7,
buttonW,
buttonH,
18
);
ctx.fill();
/* Button */
const buttonGradient=
ctx.createLinearGradient(
0,
buttonY,
0,
buttonY+buttonH
);
buttonGradient.addColorStop(
0,
"#ffe56a"
);
buttonGradient.addColorStop(
1,
"#ff9d25"
);
ctx.fillStyle=
buttonGradient;
ctx.beginPath();
ctx.roundRect(
W/2-
buttonW/2,
buttonY,
buttonW,
buttonH,
18
);
ctx.fill();
ctx.fillStyle="#172c3b";
ctx.font=
"900 25px Arial";
ctx.fillText(
"▶ START",
W/2,
buttonY+43
);
/* =================================================
HIGH SCORE
================================================= */
const scoreW=
Math.min(
230,
W*.48
);
const scoreX=
W/2-
scoreW/2;
const scoreY=
buttonY+
buttonH+
18;
ctx.fillStyle=
"rgba(0,20,35,.55)";
ctx.beginPath();
ctx.roundRect(
scoreX,
scoreY,
scoreW,
55,
15
);
ctx.fill();
ctx.fillStyle=
"rgba(255,255,255,.7)";
ctx.font=
"bold 12px Arial";
ctx.fillText(
"HIGHEST SCORE",
W/2,
scoreY+20
);
ctx.fillStyle="#fff";
ctx.font=
"900 21px Arial";
ctx.fillText(
best,
W/2,
scoreY+43
);
/* Bottom text */
ctx.fillStyle=
"rgba(255,255,255,.6)";
ctx.font=
"12px Arial";
ctx.fillText(
"TAP START TO BEGIN",
W/2,
H*.91
);
ctx.textAlign="left";
}
/* =========================================================
MENU TOUCH
========================================================= */
function menuTouch(x,y){
const buttonW=
Math.min(
230,
W*.48
);
const buttonH=68;
const buttonY=H*.56;
if(
x>
W/2-buttonW/2 &&
x<
W/2+buttonW/2 &&
y>
buttonY &&
y<
buttonY+buttonH
){
startGame();
}
}
/* =========================================================
START GAME
========================================================= */
function startGame(){
score=0;
speed=3.2;
difficulty=0;
obstacles=[];
particles=[];
resetPlane();
crashed=false;
gameStarted=true;
screen="game";
createObstacle();
}
/* =========================================================
PLAYER FLIGHT
========================================================= */
function fly(){
if(screen==="menu"){
return;
}
if(screen!=="game")
return;
if(crashed){
startGame();
return;
}
plane.vy=-7.5;
for(let i=0;i<7;i++){
particles.push({
x:
plane.x-30,
y:
plane.y+
(Math.random()-.5)*10,
vx:
-1-
Math.random()*3,
vy:
(Math.random()-.5)*2,
life:1,
size:
2+
Math.random()*4
});
}
}
/* =========================================================
CONTROLS
========================================================= */
canvas.addEventListener(
"pointerdown",
function(e){
e.preventDefault();
if(screen==="menu"){
menuTouch(
e.clientX,
e.clientY
);
return;
}
fly();
}
);
addEventListener(
"keydown",
function(e){
if(
e.code==="Space" ||
e.code==="ArrowUp" ||
e.code==="Enter"
){
e.preventDefault();
if(screen==="menu"){
startGame();
}else{
fly();
}
}
}
);
/* =========================================================
OBSTACLE
========================================================= */
function createObstacle(){
difficulty=
Math.floor(score/5);
const gap=
Math.max(
112,
205-
difficulty*8
);
const minTop=60;
const maxTop=
H-
gap-
95;
const top=
minTop+
Math.random()*
Math.max(
20,
maxTop-minTop
);
const width=
65+
Math.random()*38;
obstacles.push({
x:W+100,
width:width,
top:top,
gap:gap,
passed:false
});
}
/* =========================================================
COLLISION
========================================================= */
function collision(){
if(
plane.y-
plane.height*.45<0
)
return true;
if(
plane.y+
plane.height*.45>
H-55
)
return true;
for(const o of obstacles){
const px1=
plane.x-
plane.width*.36;
const px2=
plane.x+
plane.width*.36;
const py1=
plane.y-
plane.height*.36;
const py2=
plane.y+
plane.height*.36;
if(
px2>o.x &&
px1<o.x+o.width
){
if(
py1<o.top ||
py2>o.top+o.gap
){
return true;
}
}
}
return false;
}
/* =========================================================
UPDATE GAME
========================================================= */
function updateGame(){
if(!gameStarted || crashed)
return;
plane.vy+=.37;
plane.vy=
Math.min(
plane.vy,
9
);
plane.y+=plane.vy;
plane.vx+=
(speed-plane.vx)*.02;
plane.x+=
plane.vx*.02;
plane.x=
Math.max(
W*.14,
Math.min(
W*.36,
plane.x
)
);
let target=
plane.vy*.065;
target=
Math.max(
-.55,
Math.min(
.8,
target
)
);
plane.angle+=
(target-plane.angle)*.13;
/* Difficulty */
difficulty=
Math.floor(score/5);
const targetSpeed=
3.2+
difficulty*.32;
speed+=
(targetSpeed-speed)*.015;
speed=
Math.min(
speed,
10
);
/* Obstacles */
for(
let i=
obstacles.length-1;
i>=0;
i--
){
const o=
obstacles[i];
o.x-=speed;
if(
!o.passed &&
o.x+o.width<
plane.x
){
o.passed=true;
score++;
if(score>best){
best=score;
localStorage.setItem(
"skyPilotBest",
best
);
}
}
if(
o.x+o.width<
-120
){
obstacles.splice(
i,
1
);
}
}
const spawnDistance=
Math.max(
175,
315-
difficulty*10
);
if(
obstacles.length===0 ||
obstacles[
obstacles.length-1
].x<
W-spawnDistance
){
createObstacle();
}
if(collision()){
crash();
}
}
/* =========================================================
PARTICLES
========================================================= */
function updateParticles(){
for(
let i=
particles.length-1;
i>=0;
i--
){
const p=
particles[i];
p.x+=p.vx;
p.y+=p.vy;
p.vy+=.06;
p.life-=.025;
if(p.life<=0){
particles.splice(
i,
1
);
}
}
}
/* =========================================================
GAME SKY
========================================================= */
function drawGameSky(){
const g=
ctx.createLinearGradient(
0,
0,
0,
H
);
g.addColorStop(
0,
"#31bdf4"
);
g.addColorStop(
.55,
"#9ce8ff"
);
g.addColorStop(
1,
"#eafaff"
);
ctx.fillStyle=g;
ctx.fillRect(
0,
0,
W,
H
);
ctx.fillStyle=
"#ffe46b";
ctx.beginPath();
ctx.arc(
W*.82,
H*.15,
48,
0,
Math.PI*2
);
ctx.fill();
for(const c of clouds){
c.x-=c.speed;
if(c.x<-180)
c.x=W+100;
drawCloudGame(c);
}
}
/* =========================================================
GAME CLOUD
========================================================= */
function drawCloudGame(c){
ctx.save();
ctx.translate(
c.x,
c.y
);
ctx.scale(
c.size,
c.size
);
ctx.fillStyle=
"rgba(255,255,255,.8)";
ctx.beginPath();
ctx.arc(
-35,
7,
25,
0,
Math.PI*2
);
ctx.arc(
0,
-7,
34,
0,
Math.PI*2
);
ctx.arc(
36,
7,
25,
0,
Math.PI*2
);
ctx.fill();
ctx.restore();
}
/* =========================================================
GAME CITY
========================================================= */
function drawGameCity(){
const ground=H-55;
for(
let x=0;
x<W;
x+=45
){
const h=
45+
((x*31)%105);
ctx.fillStyle=
"#638897";
ctx.fillRect(
x,
ground-h,
37,
h
);
ctx.fillStyle=
"rgba(230,250,255,.8)";
for(
let y=
ground-h+14;
y<
ground-8;
y+=22
){
ctx.fillRect(
x+7,
y,
6,
9
);
ctx.fillRect(
x+23,
y,
6,
9
);
}
}
ctx.fillStyle="#3ba548";
ctx.fillRect(
0,
H-55,
W,
55
);
ctx.fillStyle="#555b60";
ctx.fillRect(
0,
H-30,
W,
30
);
ctx.strokeStyle="#fff";
ctx.lineWidth=3;
const offset=
-(frame*speed*.8)%70;
for(
let x=offset;
x<W;
x+=70
){
ctx.beginPath();
ctx.moveTo(
x,
H-15
);
ctx.lineTo(
x+35,
H-15
);
ctx.stroke();
}
}
/* =========================================================
OBSTACLE DRAW
========================================================= */
function drawObstacle(o){
ctx.fillStyle="#405a66";
ctx.fillRect(
o.x,
0,
o.width,
o.top
);
ctx.fillStyle="#293f49";
ctx.fillRect(
o.x-7,
o.top-18,
o.width+14,
18
);
ctx.fillStyle="#d8edf2";
for(
let y=18;
y<o.top-25;
y+=25
){
ctx.fillRect(
o.x+10,
y,
12,
10
);
ctx.fillRect(
o.x+o.width-22,
y,
12,
10
);
}
const bottom=
o.top+o.gap;
ctx.fillStyle="#405a66";
ctx.fillRect(
o.x,
bottom,
o.width,
H-bottom
);
ctx.fillStyle="#293f49";
ctx.fillRect(
o.x-7,
bottom,
o.width+14,
18
);
ctx.fillStyle="#d8edf2";
for(
let y=bottom+30;
y<H-65;
y+=25
){
ctx.fillRect(
o.x+10,
y,
12,
10
);
ctx.fillRect(
o.x+o.width-22,
y,
12,
10
);
}
}
/* =========================================================
PLANE
========================================================= */
function drawPlane(){
ctx.save();
ctx.translate(
plane.x,
plane.y
);
ctx.rotate(
plane.angle
);
ctx.fillStyle=
"rgba(0,0,0,.15)";
ctx.beginPath();
ctx.ellipse(
0,
25,
38,
7,
0,
0,
Math.PI*2
);
ctx.fill();
/* Body */
ctx.fillStyle="#f2f4f5";
ctx.beginPath();
ctx.moveTo(-38,-2);
ctx.lineTo(-18,-13);
ctx.lineTo(25,-10);
ctx.lineTo(40,0);
ctx.lineTo(25,10);
ctx.lineTo(-18,13);
ctx.closePath();
ctx.fill();
/* Nose */
ctx.fillStyle="#e43737";
ctx.beginPath();
ctx.moveTo(22,-10);
ctx.lineTo(43,0);
ctx.lineTo(22,10);
ctx.closePath();
ctx.fill();
/* Wings */
ctx.fillStyle="#d62832";
ctx.beginPath();
ctx.moveTo(0,-5);
ctx.lineTo(-26,-34);
ctx.lineTo(-10,-29);
ctx.lineTo(13,-6);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(0,5);
ctx.lineTo(-26,34);
ctx.lineTo(-10,29);
ctx.lineTo(13,6);
ctx.closePath();
ctx.fill();
/* Tail */
ctx.fillStyle="#c9252d";
ctx.beginPath();
ctx.moveTo(-28,-4);
ctx.lineTo(-39,-23);
ctx.lineTo(-27,-18);
ctx.lineTo(-17,-5);
ctx.closePath();
ctx.fill();
/* Cockpit */
ctx.fillStyle="#42bfe6";
ctx.beginPath();
ctx.ellipse(
7,
-5,
11,
6,
0,
0,
Math.PI*2
);
ctx.fill();
/* Engine */
ctx.fillStyle="#657178";
ctx.beginPath();
ctx.arc(
-3,
11,
6,
0,
Math.PI*2
);
ctx.fill();
/* Flame */
ctx.fillStyle=
frame%8<4
?
"#ffd22b"
:
"#ff711c";
ctx.beginPath();
ctx.moveTo(-8,11);
ctx.lineTo(-32,12);
ctx.lineTo(-10,18);
ctx.closePath();
ctx.fill();
ctx.restore();
}
/* =========================================================
PARTICLES
========================================================= */
function drawParticles(){
for(const p of particles){
ctx.globalAlpha=
Math.max(0,p.life);
ctx.fillStyle=
p.size>3
?
"#ff7020"
:
"#ffd329";
ctx.beginPath();
ctx.arc(
p.x,
p.y,
p.size,
0,
Math.PI*2
);
ctx.fill();
}
ctx.globalAlpha=1;
}
/* =========================================================
GAME HUD
========================================================= */
function drawHUD(){
ctx.fillStyle=
"rgba(0,0,0,.23)";
ctx.beginPath();
ctx.roundRect(
12,
12,
155,
48,
12
);
ctx.fill();
ctx.fillStyle="#fff";
ctx.font="bold 19px Arial";
ctx.fillText(
"SCORE "+score,
27,
43
);
ctx.fillStyle=
"rgba(0,0,0,.23)";
ctx.beginPath();
ctx.roundRect(
W-155,
12,
143,
48,
12
);
ctx.fill();
ctx.fillStyle="#fff";
ctx.fillText(
"BEST "+best,
W-140,
43
);
/* Speed */
const percent=
Math.min(
100,
((speed-3.2)/6.8)*100
);
ctx.fillStyle=
"rgba(0,0,0,.28)";
ctx.fillRect(
12,
70,
155,
12
);
ctx.fillStyle="#ffd12b";
ctx.fillRect(
12,
70,
155*percent/100,
12
);
ctx.fillStyle="#fff";
ctx.font="bold 11px Arial";
ctx.fillText(
"SPEED",
174,
80
);
}
/* =========================================================
CRASH
========================================================= */
function crash(){
if(crashed)
return;
crashed=true;
shake=20;
for(let i=0;i<45;i++){
particles.push({
x:plane.x,
y:plane.y,
vx:
(Math.random()-.5)*10,
vy:
(Math.random()-.5)*10,
life:1,
size:
2+
Math.random()*6
});
}
if(score>best){
best=score;
localStorage.setItem(
"skyPilotBest",
best
);
}
}
/* =========================================================
GAME OVER
========================================================= */
function drawGameOver(){
if(!crashed)
return;
ctx.fillStyle=
"rgba(0,0,0,.5)";
ctx.fillRect(
0,
0,
W,
H
);
ctx.textAlign="center";
ctx.fillStyle="#fff";
ctx.font=
"900 44px Arial";
ctx.fillText(
"CRASH!",
W/2,
H*.39
);
ctx.font=
"bold 23px Arial";
ctx.fillText(
"SCORE "+score,
W/2,
H*.47
);
ctx.fillText(
"BEST "+best,
W/2,
H*.52
);
ctx.font=
"bold 18px Arial";
ctx.fillText(
"TAP TO RESTART",
W/2,
H*.61
);
ctx.textAlign="left";
}
/* =========================================================
MAIN UPDATE
========================================================= */
function update(){
frame++;
updateUnity();
updateLoading();
if(screen==="game"){
updateGame();
}
updateParticles();
}
/* =========================================================
MAIN DRAW
========================================================= */
function draw(){
ctx.clearRect(
0,
0,
W,
H
);
if(screen==="unity"){
drawUnityScreen();
}
else if(screen==="loading"){
drawLoadingScreen();
}
else if(screen==="menu"){
drawMenu();
}
else if(screen==="game"){
ctx.save();
if(shake>0){
ctx.translate(
(Math.random()-.5)*shake,
(Math.random()-.5)*shake
);
shake*=.88;
}
drawGameSky();
drawGameCity();
for(const o of obstacles){
drawObstacle(o);
}
drawParticles();
drawPlane();
ctx.restore();
drawHUD();
drawGameOver();
}
}
/* =========================================================
LOOP
========================================================= */
function loop(){
update();
draw();
requestAnimationFrame(loop);
}
resetPlane();
loop();
</script>
</body>
</html>Game Source: Sky Pilot X
Creator: CrystalTiger19
Libraries: none
Complexity: complex (2495 lines, 30.7 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-pilot-x-crystaltiger19" to link back to the original. Then publish at arcadelab.ai/publish.