🎮ArcadeLab

Super Runner

by RapidGecko49
261 lines5.2 KB
▶ Play
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Super Runner</title>
<style>
body {
  margin: 0;
  background: #15152e;
  color: white;
  text-align: center;
  font-family: Arial, sans-serif;
}
h2 { color: #ffe45c; }
canvas {
  background: #70d6ff;
  width: 95%;
  max-width: 400px;
  height: 520px;
  border: 3px solid white;
  border-radius: 12px;
  touch-action: none;
}
button {
  padding: 13px 20px;
  margin: 5px;
  font-size: 18px;
  border: none;
  border-radius: 10px;
  background: #ffcc00;
  font-weight: bold;
}
</style>
</head>
<body>

<h2>🏃 SUPER RUNNER 🏃</h2>
<p>Coins: <span id="score">0</span></p>

<canvas id="game" width="400" height="520"></canvas>

<div>
  <button onclick="move(-1)">⬅️ Left</button>
  <button onclick="jump()">⬆️ Jump</button>
  <button onclick="move(1)">Right ➡️</button>
</div>
<button onclick="restart()">🔄 Restart</button>
<p>Collect coins and dodge the obstacles!</p>

<script>
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");

let lane = 1;
let playerY = 420;
let jumping = false;
let jumpHeight = 0;
let objects = [];
let score = 0;
let speed = 4;
let gameOver = false;
let frame = 0;

function move(dir) {
  if (!gameOver) lane = Math.max(0, Math.min(2, lane + dir));
}

function jump() {
  if (!jumping && !gameOver) {
    jumping = true;
    jumpHeight = 105;
  }
}

function restart() {
  lane = 1;
  playerY = 420;
  jumping = false;
  jumpHeight = 0;
  objects = [];
  score = 0;
  speed = 4;
  gameOver = false;
  frame = 0;
  document.getElementById("score").textContent = score;
}

document.addEventListener("keydown", e => {
  if (e.key === "ArrowLeft") move(-1);
  if (e.key === "ArrowRight") move(1);
  if (e.key === "ArrowUp" || e.key === " ") jump();
  if (e.key.toLowerCase() === "r") restart();
});

function drawPlayer() {
  const x = 80 + lane * 120;
  const y = playerY - jumpHeight;

  ctx.fillStyle = "#ff8c42";
  ctx.fillRect(x - 15, y + 35, 30, 32);

  ctx.fillStyle = "#ffd6a5";
  ctx.beginPath();
  ctx.arc(x, y + 20, 17, 0, Math.PI * 2);
  ctx.fill();

  ctx.fillStyle = "#2878ff";
  ctx.fillRect(x - 19, y + 48, 13, 25);
  ctx.fillRect(x + 6, y + 48, 13, 25);

  ctx.fillStyle = "#222";
  ctx.fillRect(x - 21, y + 70, 17, 7);
  ctx.fillRect(x + 5, y + 70, 17, 7);
}

function drawRoad() {
  ctx.fillStyle = "#39a96b";
  ctx.fillRect(0, 0, 400, 520);

  ctx.fillStyle = "#555";
  ctx.beginPath();
  ctx.moveTo(100, 0);
  ctx.lineTo(300, 0);
  ctx.lineTo(390, 520);
  ctx.lineTo(10, 520);
  ctx.closePath();
  ctx.fill();

  ctx.strokeStyle = "#fff";
  ctx.lineWidth = 4;
  ctx.setLineDash([22, 18]);

  ctx.beginPath();
  ctx.moveTo(166, 0);
  ctx.lineTo(135, 520);
  ctx.stroke();

  ctx.beginPath();
  ctx.moveTo(234, 0);
  ctx.lineTo(265, 520);
  ctx.stroke();

  ctx.setLineDash([]);
}

function spawnObject() {
  const laneIndex = Math.floor(Math.random() * 3);
  const isCoin = Math.random() < 0.55;

  objects.push({
    lane: laneIndex,
    y: -20,
    coin: isCoin,
    hit: false
  });
}

function drawObjects() {
  for (let i = objects.length - 1; i >= 0; i--) {
    const o = objects[i];
    const x = 80 + o.lane * 120;

    o.y += speed;

    if (o.coin) {
      ctx.fillStyle = "#ffe600";
      ctx.beginPath();
      ctx.arc(x, o.y, 13, 0, Math.PI * 2);
      ctx.fill();

      ctx.fillStyle = "#b87500";
      ctx.font = "bold 16px Arial";
      ctx.fillText("$", x - 5, o.y + 6);
    } else {
      ctx.fillStyle = "#e63946";
      ctx.fillRect(x - 24, o.y - 18, 48, 36);
      ctx.fillStyle = "#fff";
      ctx.fillRect(x - 18, o.y - 10, 36, 7);
    }

    const sameLane = o.lane === lane;
    const nearPlayer = o.y > 385 && o.y < 465;

    if (sameLane && nearPlayer && !o.hit) {
      if (o.coin) {
        score++;
        document.getElementById("score").textContent = score;
        o.hit = true;
      } else if (jumpHeight < 45) {
        gameOver = true;
      }
    }

    if (o.y > 550) objects.splice(i, 1);
  }
}

function loop() {
  drawRoad();

  if (!gameOver) {
    frame++;

    if (frame % 42 === 0) spawnObject();
    if (frame % 500 === 0) speed += 0.5;

    if (jumping) {
      jumpHeight -= 7;
      if (jumpHeight <= 0) {
        jumpHeight = 0;
        jumping = false;
      }
    }

    drawObjects();
    drawPlayer();
  } else {
    drawObjects();
    drawPlayer();

    ctx.fillStyle = "rgba(0,0,0,0.75)";
    ctx.fillRect(25, 190, 350, 130);

    ctx.fillStyle = "#ffe45c";
    ctx.font = "bold 32px Arial";
    ctx.fillText("GAME OVER!", 78, 240);

    ctx.fillStyle = "#fff";
    ctx.font = "20px Arial";
    ctx.fillText("Coins: " + score, 145, 275);
    ctx.fillText("Press Restart", 128, 302);
  }

  requestAnimationFrame(loop);
}

let touchStartX = 0;
let touchStartY = 0;

canvas.addEventListener("touchstart", e => {
  touchStartX = e.changedTouches[0].clientX;
  touchStartY = e.changedTouches[0].clientY;
}, {passive: true});

canvas.addEventListener("touchend", e => {
  const dx = e.changedTouches[0].clientX - touchStartX;
  const dy = e.changedTouches[0].clientY - touchStartY;

  if (Math.abs(dx) > Math.abs(dy)) {
    if (dx > 25) move(1);
    if (dx < -25) move(-1);
  } else if (dy < -25) {
    jump();
  }
}, {passive: true});

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

Game Source: Super Runner

Creator: RapidGecko49

Libraries: none

Complexity: complex (261 lines, 5.2 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: super-runner-rapidgecko49" to link back to the original. Then publish at arcadelab.ai/publish.