🎮ArcadeLab

GEOMETRY RUSH

by BoldPenguin14
485 lines7.6 KB
▶ Play

<!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>GEOMETRY RUSH</title>
<style>
*{box-sizing:border-box}
body{
 margin:0;
 background:#080817;
 color:white;
 font-family:Arial;
 display:flex;
 justify-content:center;
 align-items:center;
 min-height:100vh;
 overflow:hidden;
}
#game{
 width:min(95vw,440px);
 background:#11112b;
 border:2px solid #744cff;
 border-radius:18px;
 overflow:hidden;
 box-shadow:0 0 35px #623cff55;
}
header{
 display:flex;
 justify-content:space-around;
 padding:16px 5px;
 color:#65f5ff;
 font-weight:bold;
}
canvas{
 width:100%;
 display:block;
 background:#10102b;
 touch-action:none;
}
#controls{
 padding:13px;
 display:flex;
 justify-content:center;
}
button{
 border:0;
 border-radius:30px;
 padding:16px 55px;
 background:linear-gradient(90deg,#00d9ff,#9745ff);
 color:white;
 font-size:19px;
 font-weight:bold;
 cursor:pointer;
 touch-action:none;
}
#menu{
 position:fixed;
 inset:0;
 background:#080817ee;
 display:flex;
 justify-content:center;
 align-items:center;
 flex-direction:column;
 text-align:center;
 z-index:5;
 padding:20px;
}
h1{
 color:#65f5ff;
 font-size:39px;
 text-shadow:0 0 20px cyan;
}
#menu p{color:#ccc;line-height:1.6}
#menu button{padding:18px 45px}
</style>
</head>
<body>

<div id="game">
<header>
<div>SCORE<br><span id="score">0</span></div>
<div>BEST<br><span id="best">0</span></div>
<div>LEVEL<br><span id="level">1</span></div>
</header>

<canvas id="c" width="400" height="500"></canvas>

<div id="controls">
<button id="jump">JUMP! ▲</button>
</div>
</div>

<div id="menu">
<h1 id="heading">GEOMETRY<br>RUSH!</h1>
<p id="message">
Jump over spikes.<br>
Don't crash!<br><br>
Tap or press SPACE to jump.
</p>
<button id="start">PLAY NOW</button>
</div>

<script>
(()=>{
const canvas=document.getElementById("c");
const ctx=canvas.getContext("2d");
const $=id=>document.getElementById(id);

const W=400,H=500,ground=410;

let player,obstacles,coins;
let score=0,best=0,level=1;
let speed=5,frame=0;
let running=false,raf=0;
let particles=[];

try{
 best=Number(localStorage.getItem("geometryBest"))||0;
}catch(e){}

$("best").textContent=best;

function startGame(){
 cancelAnimationFrame(raf);

 player={
  x:75,
  y:ground-30,
  size:30,
  vy:0,
  grounded:true,
  rotation:0
 };

 obstacles=[];
 coins=[];
 particles=[];

 score=0;
 level=1;
 speed=5;
 frame=0;
 running=true;

 $("menu").style.display="none";
 $("score").textContent=0;
 $("level").textContent=1;

 loop();
}

function jump(){
 if(!running)return;

 if(player.grounded){
  player.vy=-12.5;
  player.grounded=false;
  burst(player.x+15,player.y+25,"#65f5ff",7);
 }
}

function burst(x,y,color,count){
 for(let i=0;i<count;i++){
  particles.push({
   x,y,
   vx:(Math.random()-.5)*6,
   vy:(Math.random()-.5)*6,
   life:25,
   color
  });
 }
}

function gameOver(){
 running=false;
 cancelAnimationFrame(raf);

 best=Math.max(best,score);

 try{
  localStorage.setItem("geometryBest",best);
 }catch(e){}

 $("best").textContent=best;
 $("heading").innerHTML="YOU CRASHED!";
 $("message").innerHTML=
 "⭐ Score: "+score+
 "<br>🏆 Best: "+best+
 "<br>Level reached: "+level;

 $("start").textContent="TRY AGAIN";
 $("menu").style.display="flex";
}

function spawnObstacle(){
 const type=Math.random();

 if(type<.75){
  obstacles.push({
   x:420,
   y:ground,
   w:30+Math.random()*12,
   h:35+Math.random()*15,
   type:"spike"
  });
 }else{
  obstacles.push({
   x:420,
   y:ground-35,
   w:35,
   h:35,
   type:"block"
  });
 }
}

function drawBackground(){

 ctx.fillStyle="#10102b";
 ctx.fillRect(0,0,W,H);

 // Background grid
 ctx.strokeStyle="#25254b";
 ctx.lineWidth=1;

 for(let x=0;x<W;x+=40){
  ctx.beginPath();
  ctx.moveTo(x,0);
  ctx.lineTo(x,H);
  ctx.stroke();
 }

 for(let y=0;y<H;y+=40){
  ctx.beginPath();
  ctx.moveTo(0,y);
  ctx.lineTo(W,y);
  ctx.stroke();
 }

 // Moving background decoration
 ctx.fillStyle="#29245c";

 for(let i=0;i<8;i++){
  let x=(i*90-frame*0.5)%480;
  if(x<0)x+=480;

  ctx.fillRect(x,300,3,70);
 }

 // Ground
 ctx.fillStyle="#27245b";
 ctx.fillRect(0,ground,W,H-ground);

 ctx.fillStyle="#65f5ff";
 ctx.fillRect(0,ground,W,3);
}

function drawPlayer(){

 ctx.save();

 ctx.translate(
  player.x+15,
  player.y+15
 );

 ctx.rotate(player.rotation);

 ctx.shadowColor="#00eaff";
 ctx.shadowBlur=20;

 ctx.fillStyle="#65f5ff";
 ctx.fillRect(-15,-15,30,30);

 ctx.shadowBlur=0;

 ctx.fillStyle="#171735";

 ctx.fillRect(-9,-7,5,7);
 ctx.fillRect(4,-7,5,7);

 ctx.restore();
}

function loop(){
 if(!running)return;

 frame++;

 score++;
 level=1+Math.floor(score/500);

 speed=5+level*.65;

 $("score").textContent=score;
 $("level").textContent=level;

 // Gravity and jumping
 player.vy+=.65;
 player.y+=player.vy;

 if(player.y>=ground-player.size){
  player.y=ground-player.size;
  player.vy=0;
  player.grounded=true;
 }

 if(!player.grounded){
  player.rotation+=.09;
 }else{
  player.rotation=Math.round(player.rotation/(Math.PI/2))*(Math.PI/2);
 }

 // Spawn obstacles
 let spawnRate=Math.max(35,90-level*4);

 if(frame%spawnRate===0){
  spawnObstacle();
 }

 // Spawn coins
 if(frame%110===0){
  coins.push({
   x:430,
   y:ground-90-Math.random()*70,
   r:9
  });
 }

 // Move obstacles
 for(let i=obstacles.length-1;i>=0;i--){
  let o=obstacles[i];
  o.x-=speed;

  // Collision detection
  let px=player.x+5;
  let py=player.y+5;
  let pw=player.size-10;
  let ph=player.size-10;

  if(o.type==="block"){
   if(px<o.x+o.w &&
      px+pw>o.x &&
      py<o.y+o.h &&
      py+ph>o.y){
    gameOver();
    return;
   }
  }else{
   // Spike collision
   let hitX=px+pw>o.x+5 && px<o.x+o.w-5;
   let hitY=py+ph>ground-o.h+12;

   if(hitX && hitY){
    gameOver();
    return;
   }
  }

  if(o.x+o.w<0){
   obstacles.splice(i,1);
  }
 }

 // Move coins
 for(let i=coins.length-1;i>=0;i--){
  let c=coins[i];
  c.x-=speed;

  let distance=Math.hypot(
   player.x+15-c.x,
   player.y+15-c.y
  );

  if(distance<25){
   score+=50;
   burst(c.x,c.y,"#ffe45c",12);
   coins.splice(i,1);
   continue;
  }

  if(c.x<0)coins.splice(i,1);
 }

 // Particles
 for(let i=particles.length-1;i>=0;i--){
  let p=particles[i];
  p.x+=p.vx;
  p.y+=p.vy;
  p.life--;

  if(p.life<=0)particles.splice(i,1);
 }

 drawBackground();

 // Obstacles
 obstacles.forEach(o=>{
  if(o.type==="spike"){
   ctx.shadowColor="#ff2255";
   ctx.shadowBlur=18;
   ctx.fillStyle="#ff285c";

   ctx.beginPath();
   ctx.moveTo(o.x,ground);
   ctx.lineTo(o.x+o.w/2,ground-o.h);
   ctx.lineTo(o.x+o.w,ground);
   ctx.closePath();
   ctx.fill();

  }else{
   ctx.shadowColor="#ff2255";
   ctx.shadowBlur=18;
   ctx.fillStyle="#ff285c";
   ctx.fillRect(o.x,o.y,o.w,o.h);
  }
 });

 ctx.shadowBlur=0;

 // Coins
 coins.forEach(c=>{
  ctx.shadowColor="#ffe45c";
  ctx.shadowBlur=20;
  ctx.fillStyle="#ffe45c";

  ctx.beginPath();
  ctx.arc(c.x,c.y,c.r,0,Math.PI*2);
  ctx.fill();

  ctx.shadowBlur=0;
 });

 // Player
 drawPlayer();

 // Particles
 particles.forEach(p=>{
  ctx.globalAlpha=Math.max(0,p.life/25);
  ctx.fillStyle=p.color;
  ctx.fillRect(p.x,p.y,5,5);
 });
 ctx.globalAlpha=1;

 // Speed indicator
 ctx.fillStyle="#65f5ff";
 ctx.font="bold 13px Arial";
 ctx.fillText("SPEED x"+(speed/5).toFixed(1),15,25);

 raf=requestAnimationFrame(loop);
}

// Controls
$("jump").addEventListener("pointerdown",e=>{
 e.preventDefault();
 jump();
});

canvas.addEventListener("pointerdown",e=>{
 e.preventDefault();
 jump();
});

document.addEventListener("keydown",e=>{
 if(["Space","ArrowUp","KeyW"].includes(e.code)){
  e.preventDefault();
  jump();
 }
});

$("start").addEventListener("click",startGame);

$("menu").addEventListener("click",e=>{
 if(e.target===$("menu") && !running)startGame();
});

drawBackground();

})();
</script>
</body>
</html>

Game Source: GEOMETRY RUSH

Creator: BoldPenguin14

Libraries: none

Complexity: complex (485 lines, 7.6 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: geometry-rush-boldpenguin14" to link back to the original. Then publish at arcadelab.ai/publish.