🎮ArcadeLab

Satyam Endless Runner

by FrozenFlare95
404 lines9.7 KB
▶ Play
<!DOCTYPE html>
<html lang="hi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Satyam Endless Runner</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{
  background:#111;
  overflow:hidden;
  font-family:Arial,sans-serif;
  touch-action:none;
}
#game{
  width:100vw;height:100vh;position:relative;overflow:hidden;
  background:linear-gradient(#54c9ff 0%,#b9f0ff 48%,#55b957 49%,#23852e 100%);
}
#sky{
  position:absolute;inset:0;
  background:
  radial-gradient(circle at 20% 20%,#fff 0 28px,transparent 29px),
  radial-gradient(circle at 75% 15%,#fff 0 22px,transparent 23px);
  opacity:.65;
}
#road{
  position:absolute;
  left:12%;right:12%;top:0;bottom:0;
  background:#555;
  overflow:hidden;
  perspective:500px;
}
.track{
  position:absolute;left:33.33%;width:33.34%;height:100%;
  border-left:8px solid #ddd;border-right:8px solid #ddd;
}
.rail{
  position:absolute;top:0;bottom:0;width:7px;background:#bbb;
}
.rail.a{left:33.33%}.rail.b{left:66.66%}
.sleepers{
  position:absolute;inset:0;
  background:repeating-linear-gradient(
    to bottom,transparent 0 55px,#382b20 56px 68px
  );
  opacity:.8;
}
.lane{
  position:absolute;top:0;width:4px;height:100%;
  background:repeating-linear-gradient(to bottom,#fff 0 45px,transparent 45px 90px);
  opacity:.45;
}
.lane.l{left:33.33%}.lane.r{left:66.66%}

#player{
  position:absolute;
  width:58px;height:88px;
  bottom:105px;left:calc(50% - 29px);
  z-index:20;
  transition:left .12s;
}
.head{
  width:35px;height:35px;border-radius:50%;
  background:#c98252;margin:auto;border:3px solid #222;
}
.body{
  width:40px;height:38px;background:#1769d1;
  margin:2px auto;border-radius:9px;
}
.leg{
  position:absolute;width:12px;height:25px;background:#222;bottom:0;border-radius:5px;
}
.leg1{left:12px}.leg2{right:12px}
.name{
  position:absolute;top:-23px;left:50%;
  transform:translateX(-50%);
  color:#fff;font-weight:bold;font-size:15px;
  text-shadow:2px 2px 3px #000;
}
.jump{bottom:220px}
.slide{height:45px;bottom:105px}
.slide .head{width:28px;height:28px}
.slide .body{height:25px}

.object{
  position:absolute;
  width:64px;height:64px;
  z-index:15;
}
.coin{
  border-radius:50%;
  background:radial-gradient(circle,#fff36b 0 15%,#ffc400 17% 65%,#b87900 67%);
  border:4px solid #ffea00;
  box-shadow:0 0 15px #ffd000;
}
.train{
  width:82px;height:115px;
  background:linear-gradient(90deg,#d71920,#ff5757,#a50000);
  border:4px solid #222;border-radius:12px;
}
.train:before{
  content:"";
  display:block;width:52px;height:38px;
  margin:10px auto;background:#8eeaff;border:4px solid #222;
}
.barrier{
  width:80px;height:35px;
  background:repeating-linear-gradient(135deg,#fff 0 12px,#ed2024 12px 24px);
  border:3px solid #222;border-radius:6px;
}
.plane{
  width:90px;height:42px;
  background:#fff;border-radius:50% 50% 20% 20%;
  border:3px solid #555;
}
.plane:after{
  content:"✈";
  font-size:45px;color:#1976d2;
  position:absolute;left:20px;top:-12px;
}

#chaser{
  position:absolute;bottom:20px;left:calc(50% - 30px);
  font-size:42px;z-index:18;
  transition:.2s;
}
#hud{
  position:absolute;top:15px;left:15px;right:15px;
  z-index:50;display:flex;justify-content:space-between;
  color:#fff;font-weight:bold;font-size:19px;
  text-shadow:2px 2px 4px #000;
}
#message{
  position:absolute;inset:0;z-index:100;
  display:flex;align-items:center;justify-content:center;
  background:rgba(0,0,0,.65);
  color:#fff;text-align:center;
}
.panel{
  background:#18202b;border:3px solid #ffc400;
  border-radius:20px;padding:28px;max-width:330px;
}
.panel h1{color:#ffd000;margin-bottom:12px}
button{
  border:0;border-radius:12px;
  padding:13px 25px;margin-top:18px;
  font-size:18px;font-weight:bold;
  background:#ffc400;color:#111;
}
.controls{
  position:absolute;bottom:15px;left:15px;right:15px;
  z-index:60;display:flex;justify-content:space-between;
}
.controls button{
  width:70px;height:55px;padding:0;margin:0;
  background:rgba(0,0,0,.55);color:#fff;
  border:2px solid #fff;font-size:25px;
}
.hidden{display:none!important}
</style>
</head>

<body>
<div id="game">
  <div id="sky"></div>
  <div id="road">
    <div class="track"></div>
    <div class="rail a"></div>
    <div class="rail b"></div>
    <div class="sleepers"></div>
    <div class="lane l"></div>
    <div class="lane r"></div>
  </div>

  <div id="player">
    <div class="name">SATYAM</div>
    <div class="head"></div>
    <div class="body"></div>
    <div class="leg leg1"></div>
    <div class="leg leg2"></div>
  </div>

  <div id="chaser">🏃‍♂️</div>

  <div id="hud">
    <div>🏃 SATYAM</div>
    <div>🪙 <span id="coins">0</span></div>
    <div>🏆 <span id="score">0</span></div>
  </div>

  <div class="controls">
    <button id="left">◀</button>
    <button id="jump">▲</button>
    <button id="slide">▼</button>
    <button id="right">▶</button>
  </div>

  <div id="message">
    <div class="panel">
      <h1 id="title">SATYAM RUNNER</h1>
      <p id="text">पटरी पर दौड़ो, coins collect करो और obstacles से बचो!</p>
      <button id="start">START GAME</button>
    </div>
  </div>
</div>

<script>
const game=document.getElementById("game");
const player=document.getElementById("player");
const scoreEl=document.getElementById("score");
const coinsEl=document.getElementById("coins");
const message=document.getElementById("message");
const title=document.getElementById("title");
const text=document.getElementById("text");
const start=document.getElementById("start");
const chaser=document.getElementById("chaser");

let running=false,score=0,coins=0,speed=7;
let lane=1,objects=[],spawnTimer=0,last=0;
let jumping=false,sliding=false;

function laneX(n){
  const w=game.clientWidth;
  return [w*.22,w*.50,w*.78][n]-32;
}

function setLane(){
  player.style.left=laneX(lane)+"px";
}

function jump(){
  if(!running||jumping||sliding)return;
  jumping=true;
  player.classList.add("jump");
  setTimeout(()=>{
    player.classList.remove("jump");
    jumping=false;
  },650);
}

function slide(){
  if(!running||jumping||sliding)return;
  sliding=true;
  player.classList.add("slide");
  setTimeout(()=>{
    player.classList.remove("slide");
    sliding=false;
  },600);
}

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

function createObject(type,l){
  const el=document.createElement("div");
  el.className="object "+type;
  el.style.left=(laneX(l)+29)+"px";
  el.style.top="-130px";
  game.appendChild(el);
  objects.push({el,type,l,y:-130});
}

function spawn(){
  const l=Math.floor(Math.random()*3);
  const r=Math.random();

  if(r<.45){
    createObject("coin",l);
  }else if(r<.70){
    createObject("barrier",l);
  }else if(r<.92){
    createObject("train",l);
  }else{
    createObject("plane",l);
  }

  if(Math.random()<.35){
    const l2=Math.floor(Math.random()*3);
    for(let i=0;i<3;i++)
      setTimeout(()=>createObject("coin",l2),i*180);
  }
}

function hit(a,b){
  const A=a.getBoundingClientRect();
  const B=b.getBoundingClientRect();
  return A.left<B.right && A.right>B.left &&
         A.top<B.bottom && A.bottom>B.top;
}

function gameOver(){
  running=false;
  title.textContent="GAME OVER 💥";
  text.innerHTML="SATYAM टकरा गया!<br><br>Score: "+score+
    "<br>Coins: "+coins;
  start.textContent="RESTART";
  message.classList.remove("hidden");
}

function update(t){
  if(!running){
    requestAnimationFrame(update);
    return;
  }

  const dt=Math.min((t-last)/16.67,2);
  last=t;

  score+=Math.floor(dt*speed/8);
  scoreEl.textContent=score;

  spawnTimer-=dt;
  if(spawnTimer<=0){
    spawn();
    spawnTimer=Math.max(32,75-speed*3);
    speed+=0.002*dt;
  }

  for(let i=objects.length-1;i>=0;i--){
    const o=objects[i];
    o.y+=speed*dt;
    o.el.style.top=o.y+"px";

    if(o.type==="coin" && hit(player,o.el)){
      coins++;
      score+=50;
      coinsEl.textContent=coins;
      o.el.remove();
      objects.splice(i,1);
      continue;
    }

    if(o.type!=="coin" && hit(player,o.el)){
      if(o.type==="barrier" && jumping) continue;
      if(o.type==="plane" && jumping) continue;
      if(o.type==="train" && jumping) continue;
      if(o.type==="barrier" && sliding) continue;
      gameOver();
      return;
    }

    if(o.y>game.clientHeight+150){
      o.el.remove();
      objects.splice(i,1);
    }
  }

  chaser.style.bottom=(20+Math.min(60,score/100))+"px";
  requestAnimationFrame(update);
}

function startGame(){
  objects.forEach(o=>o.el.remove());
  objects=[];
  score=0;coins=0;speed=7;lane=1;
  jumping=false;sliding=false;
  player.className="";
  setLane();
  scoreEl.textContent="0";
  coinsEl.textContent="0";
  message.classList.add("hidden");
  running=true;
  last=performance.now();
}

start.addEventListener("click",startGame);
document.getElementById("left").addEventListener("click",()=>move(-1));
document.getElementById("right").addEventListener("click",()=>move(1));
document.getElementById("jump").addEventListener("click",jump);
document.getElementById("slide").addEventListener("click",slide);

document.addEventListener("keydown",e=>{
  if(e.key==="ArrowLeft"||e.key==="a")move(-1);
  if(e.key==="ArrowRight"||e.key==="d")move(1);
  if(e.key==="ArrowUp"||e.key==="w"||e.key===" ")jump();
  if(e.key==="ArrowDown"||e.key==="s")slide();
});

let touchX=0,touchY=0;
game.addEventListener("touchstart",e=>{
  touchX=e.touches[0].clientX;
  touchY=e.touches[0].clientY;
},{passive:true});

game.addEventListener("touchend",e=>{
  const x=e.changedTouches[0].clientX;
  const y=e.changedTouches[0].clientY;
  const dx=x-touchX,dy=y-touchY;

  if(Math.abs(dx)>Math.abs(dy) && Math.abs(dx)>30)
    move(dx>0?1:-1);
  else if(Math.abs(dy)>30)
    dy<0?jump():slide();
},{passive:true});

window.addEventListener("resize",setLane);
setLane();
requestAnimationFrame(update);
</script>
</body>
</html>

Game Source: Satyam Endless Runner

Creator: FrozenFlare95

Libraries: none

Complexity: complex (404 lines, 9.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: satyam-endless-runner-frozenflare95" to link back to the original. Then publish at arcadelab.ai/publish.