🎮ArcadeLab

Jungle Battle Ground

by WildDragon12
746 lines20.7 KB
▶ Play

<!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>Jungle Battle Ground</title>
<style>
*{box-sizing:border-box}
html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#07120d;color:white;font-family:Arial,sans-serif;touch-action:none}
#gameWrap{position:fixed;inset:0;width:100%;height:100%;height:100dvh;background:#07120d}
canvas{display:block;width:100%;height:100%;object-fit:fill}
#hud{position:absolute;top:8px;left:8px;right:8px;display:flex;justify-content:space-between;gap:5px;flex-wrap:wrap;pointer-events:none}
.stat{background:#07140ee8;border:1px solid #7bdb8a;padding:7px 10px;border-radius:9px;font-weight:bold;font-size:clamp(11px,2vw,15px)}
button{border:2px solid #c9ffb3;border-radius:10px;background:#207d35;color:white;font-size:15px;font-weight:bold;padding:11px 15px;cursor:pointer;touch-action:manipulation}
#pauseBtn,#fullBtn{position:absolute;right:9px;padding:8px 10px;font-size:13px}
#pauseBtn{top:53px}
#fullBtn{top:96px}
#menu{position:absolute;inset:0;background:#020b08dd;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:20px;overflow:auto}
#menu h1{font-size:clamp(25px,5vw,45px);margin:5px;color:#b8ff8b;text-shadow:0 0 15px #44ff52}
#menu p{max-width:550px;line-height:1.5}
#nextBtn,#restartBtn{display:none}
#message{position:absolute;top:20%;width:100%;text-align:center;font-size:clamp(20px,5vw,38px);font-weight:bold;text-shadow:0 2px 7px black;pointer-events:none}
#controls{position:absolute;bottom:max(8px,env(safe-area-inset-bottom));left:0;right:0;display:flex;justify-content:space-between;align-items:end;padding:0 12px;pointer-events:none}
.group{display:flex;gap:7px;pointer-events:auto}
.ctrl{width:clamp(45px,9vw,65px);height:clamp(45px,9vw,65px);padding:0;border-radius:50%;background:#142a22df;border:2px solid #b6ffae;color:white;font-size:22px;user-select:none;-webkit-user-select:none}
@media(orientation:portrait){
 #controls{padding:0 8px}
 .ctrl{width:48px;height:48px}
}
</style>
</head>
<body>
<div id="gameWrap">
<canvas id="game"></canvas>

<div id="hud">
 <div class="stat" id="levelText">LEVEL 1</div>
 <div class="stat" id="scoreText">SCORE: 0</div>
 <div class="stat" id="coinText">COINS: 0</div>
 <div class="stat" id="hpText">HP: ♥♥♥</div>
</div>

<button id="pauseBtn">Ⅱ PAUSE</button>
<button id="fullBtn">⛶ FULL</button>
<div id="message"></div>

<div id="controls">
 <div class="group">
  <button class="ctrl" data-key="left">◀</button>
  <button class="ctrl" data-key="right">▶</button>
  <button class="ctrl" data-key="down">▼</button>
 </div>
 <div class="group">
  <button class="ctrl" data-key="attack">⚔</button>
  <button class="ctrl" data-key="jump">⬆</button>
 </div>
</div>

<div id="menu">
 <h1 id="menuTitle">🌴 JUNGLE BATTLE GROUND</h1>
 <p id="menuText">Jump, fight enemies and collect coins.<br>
 Level 3: Deep water 🌊<br>
 Level 6: Dangerous lava 🔥<br>
 Every new level gets harder!</p>
 <button id="startBtn">START GAME</button>
 <button id="nextBtn">NEXT LEVEL ➜</button>
 <button id="restartBtn">PLAY AGAIN</button>
</div>
</div>

<script>
const canvas=document.getElementById("game");
const ctx=canvas.getContext("2d");
const W=960,H=540;
let dpr=1;

function resizeCanvas(){
 dpr=Math.min(window.devicePixelRatio||1,2);
 canvas.width=Math.round(W*dpr);
 canvas.height=Math.round(H*dpr);
 ctx.setTransform(dpr,0,0,dpr,0,0);
}
window.addEventListener("resize",resizeCanvas);
resizeCanvas();

const $=id=>document.getElementById(id);
const menu=$("menu"),message=$("message");
const keys={left:false,right:false,down:false,jump:false,attack:false};

let level=1,score=0,coins=0,hp=3;
let running=false,paused=false,gameOver=false,won=false;
let camera=0,worldWidth=3000,frame=0;
let platforms=[],pits=[],coinItems=[],enemies=[],particles=[];
let invulnerable=0,lastJump=false,lastAttack=false;
let finishLock=false;

const player={x:60,y:300,w:32,h:48,vx:0,vy:0,onGround:false,face:1,attackTime:0};

function hazardType(){
 if(level>=6)return "lava";
 if(level>=3)return "water";
 return "pit";
}

function makeLevel(){
 worldWidth=2800+level*260;
 platforms=[];
 pits=[];
 coinItems=[];
 enemies=[];
 particles=[];
 camera=0;
 finishLock=false;

 const groundY=440;
 const type=hazardType();

 // Generate a continuous route of safe ground, pits and bridges.
 let x=0;
 let index=0;
 const finalSafeStart=worldWidth-500;

 while(x<finalSafeStart){
   const safeLength=Math.max(205,275-Math.min(level*3,45)+Math.random()*45);
   const actualSafeLength=Math.min(safeLength,finalSafeStart-x);

   if(actualSafeLength>0){
     platforms.push({
       x:x,y:groundY,w:actualSafeLength,h:100,floating:false
     });
   }
   x+=actualSafeLength;

   if(x>=finalSafeStart)break;

   // Keep hazards moderate enough to jump across.
   const pitW=Math.min(75+level*4+Math.random()*18,125);
   pits.push({
     x:x,y:groundY,w:pitW,type:type,phase:Math.random()*6
   });

   x+=pitW;

   // Guaranteed bridge across each hazard.
   // The bridge is wide and high enough for the player to land on.
   platforms.push({
     x:x-pitW+8,
     y:groundY-72,
     w:pitW+62,
     h:16,
     floating:true
   });

   // Extra stepping stone on harder levels.
   if(level>=4){
     platforms.push({
       x:x-pitW+pitW*.25,
       y:groundY-125,
       w:55,
       h:14,
       floating:true
     });
   }

   // A short safe strip immediately after every pit.
   const landingLength=85;
   platforms.push({
     x:x+5,y:groundY,w:landingLength,h:100,floating:false
   });
   x+=landingLength;
   index++;
 }

 // Wide, continuous final safe ground after the last hazard.
 platforms.push({
   x:finalSafeStart,
   y:groundY,
   w:worldWidth-finalSafeStart+200,
   h:100,
   floating:false
 });

 // Sort ground and floating platforms by x.
 platforms.sort((a,b)=>a.x-b.x);

 // Coins placed above the route.
 for(let cx=145;cx<worldWidth-140;cx+=105+Math.random()*25){
   coinItems.push({
     x:cx,
     y:330+Math.random()*55,
     r:10,
     taken:false
   });
 }

 // Enemies increase with level but stay on the safe route.
 const enemyCount=Math.min(3+level*2,24);
 for(let i=0;i<enemyCount;i++){
   const ex=350+i*((worldWidth-750)/Math.max(1,enemyCount));
   enemies.push({
     x:ex,y:390,w:30,h:40,
     vx:(Math.random()<.5?-1:1)*(1+level*.12),
     minX:Math.max(10,ex-45),
     maxX:Math.min(worldWidth-100,ex+45),
     alive:true
   });
 }

 player.x=60;
 player.y=groundY-player.h;
 player.vx=0;
 player.vy=0;
 player.onGround=true;
 player.h=48;
 player.attackTime=0;
 invulnerable=70;
 lastJump=false;
 lastAttack=false;
 updateHud();
}

function updateHud(){
 $("levelText").textContent="LEVEL "+level;
 $("scoreText").textContent="SCORE: "+score;
 $("coinText").textContent="COINS: "+coins;
 $("hpText").textContent="HP: "+("♥".repeat(Math.max(0,hp)))+("♡".repeat(Math.max(0,3-hp)));
}

function showMenu(title,text,buttons){
 $("menuTitle").textContent=title;
 $("menuText").innerHTML=text;
 menu.style.display="flex";
 $("startBtn").style.display=buttons.start?"inline-block":"none";
 $("nextBtn").style.display=buttons.next?"inline-block":"none";
 $("restartBtn").style.display=buttons.restart?"inline-block":"none";
}

function startGame(){
 level=1;score=0;coins=0;hp=3;
 gameOver=false;won=false;paused=false;
 makeLevel();
 running=true;
 menu.style.display="none";
 message.textContent="";
}

function nextLevel(){
 if(!won)return;
 level++;
 won=false;
 paused=false;
 makeLevel();
 running=true;
 menu.style.display="none";
 message.textContent="LEVEL "+level;
 setTimeout(()=>{
   if(running&&!paused)message.textContent="";
 },1200);
}

function finishLevel(){
 if(finishLock||!running)return;
 finishLock=true;
 running=false;
 won=true;
 message.textContent="";
 showMenu(
   "🏆 LEVEL "+level+" COMPLETE!",
   "Shabash! Level "+level+" complete ho gaya.<br>Kya aap Level "+(level+1)+" khelna chahte hain?<br>Agla level aur mushkil hoga!",
   {start:false,next:true,restart:false}
 );
 $("nextBtn").textContent="YES — NEXT LEVEL ➜";
}

function endGame(){
 running=false;
 gameOver=true;
 won=false;
 showMenu(
  "💀 GAME OVER",
  "Aap Level "+level+" tak pohnche!<br>Score: "+score+" | Coins: "+coins,
  {start:false,next:false,restart:true}
 );
}

$("startBtn").onclick=startGame;
$("restartBtn").onclick=startGame;
$("nextBtn").onclick=nextLevel;

$("pauseBtn").onclick=()=>{
 if(!running)return;
 paused=!paused;
 message.textContent=paused?"PAUSED":"";
 $("pauseBtn").textContent=paused?"▶ RESUME":"Ⅱ PAUSE";
};

$("fullBtn").onclick=async()=>{
 const el=$("gameWrap");
 try{
  if(!document.fullscreenElement){
   if(el.requestFullscreen)await el.requestFullscreen();
  }else{
   await document.exitFullscreen();
  }
 }catch(e){
  message.textContent="Use browser menu for full screen";
  setTimeout(()=>message.textContent="",1800);
 }
};

document.addEventListener("keydown",e=>{
 if(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"," "].includes(e.key))e.preventDefault();
 if(e.key==="ArrowLeft"||e.key.toLowerCase()==="a")keys.left=true;
 if(e.key==="ArrowRight"||e.key.toLowerCase()==="d")keys.right=true;
 if(e.key==="ArrowDown"||e.key.toLowerCase()==="s")keys.down=true;
 if(e.key==="ArrowUp"||e.key===" ")keys.jump=true;
 if(e.key.toLowerCase()==="j")keys.attack=true;
});
document.addEventListener("keyup",e=>{
 if(e.key==="ArrowLeft"||e.key.toLowerCase()==="a")keys.left=false;
 if(e.key==="ArrowRight"||e.key.toLowerCase()==="d")keys.right=false;
 if(e.key==="ArrowDown"||e.key.toLowerCase()==="s")keys.down=false;
 if(e.key==="ArrowUp"||e.key===" ")keys.jump=false;
 if(e.key.toLowerCase()==="j")keys.attack=false;
});
document.querySelectorAll(".ctrl").forEach(btn=>{
 const k=btn.dataset.key;
 const press=e=>{e.preventDefault();keys[k]=true};
 const release=e=>{e.preventDefault();keys[k]=false};
 btn.addEventListener("pointerdown",press);
 btn.addEventListener("pointerup",release);
 btn.addEventListener("pointercancel",release);
 btn.addEventListener("lostpointercapture",release);
 btn.addEventListener("contextmenu",e=>e.preventDefault());
});

function overlaps(a,b){
 return a.x<b.x+b.w&&a.x+a.w>b.x&&a.y<b.y+b.h&&a.y+a.h>b.y;
}
function addParticles(x,y,color,n=8){
 for(let i=0;i<n;i++){
  particles.push({
   x,y,vx:(Math.random()-.5)*5,
   vy:(Math.random()-.8)*5,
   life:25+Math.random()*18,color
  });
 }
}
function hurt(){
 if(invulnerable>0||!running)return;
 hp--;
 invulnerable=90;
 player.vx=-player.face*2;
 player.vy=-4;
 updateHud();
 if(hp<=0)endGame();
}

// Return true if the player has fallen into a hazard.
function checkHazards(){
 const foot=player.y+player.h;
 for(const pit of pits){
  const horizontal=player.x+player.w>pit.x+4&&player.x<pit.x+pit.w-4;
  if(horizontal&&foot>pit.y+3){
   if(pit.type==="water"){
    addParticles(player.x+player.w/2,pit.y,"#72eaff",10);
   }else if(pit.type==="lava"){
    addParticles(player.x+player.w/2,pit.y,"#ff5511",12);
   }else{
    addParticles(player.x+player.w/2,pit.y,"#b7a58b",7);
   }
   // Lose HP and return to the safe bank before the hazard.
   hurt();
   if(running){
    player.x=Math.max(5,pit.x-player.w-12);
    player.y=440-player.h;
    player.vy=0;
    player.vx=0;
    player.onGround=true;
   }
   return true;
  }
 }
 return false;
}

function update(){
 if(!running||paused)return;
 frame++;

 const speed=3.2+Math.min(level*.12,2.4);
 player.vx=0;
 if(keys.left){player.vx=-speed;player.face=-1}
 if(keys.right){player.vx=speed;player.face=1}

 player.h=(keys.down&&player.onGround)?32:48;

 if(keys.jump&&!lastJump&&player.onGround){
  player.vy=-11.5;
  player.onGround=false;
 }
 lastJump=keys.jump;

 if(keys.attack&&!lastAttack){
  player.attackTime=12;
  const box={
   x:player.face===1?player.x+player.w:player.x-35,
   y:player.y+5,w:36,h:35
  };
  for(const en of enemies){
   if(en.alive&&overlaps(box,en)){
    en.alive=false;
    score+=20;
    addParticles(en.x,en.y,"#ffcc4d",12);
   }
  }
 }
 lastAttack=keys.attack;
 if(player.attackTime>0)player.attackTime--;

 const previousBottom=player.y+player.h;
 player.x+=player.vx;
 player.x=Math.max(0,Math.min(worldWidth-player.w,player.x));

 player.vy=Math.min(player.vy+.52,13);
 player.y+=player.vy;
 player.onGround=false;

 // Land only when crossing a platform top from above.
 for(const p of platforms){
  if(player.x+player.w>p.x&&player.x<p.x+p.w&&
     previousBottom<=p.y+5&&player.y+player.h>=p.y&&player.vy>=0){
   player.y=p.y-player.h;
   player.vy=0;
   player.onGround=true;
  }
 }

 // Hazards are checked after landing physics.
 if(checkHazards())return;

 // Falling off the map also costs HP.
 if(player.y>H+60){
  hurt();
  if(running){
   player.x=Math.max(5,player.x-120);
   player.y=440-player.h;
   player.vy=0;
   player.onGround=true;
  }
 }

 for(const c of coinItems){
  if(!c.taken&&Math.abs(player.x+player.w/2-c.x)<24&&
     Math.abs(player.y+player.h/2-c.y)<30){
   c.taken=true;
   coins++;
   score+=10;
   addParticles(c.x,c.y,"#ffe96b",6);
  }
 }

 for(const en of enemies){
  if(!en.alive)continue;
  en.x+=en.vx;
  if(en.x<en.minX||en.x>en.maxX)en.vx*=-1;
  if(overlaps(player,en)){
   if(player.vy>1&&player.y+player.h<en.y+24){
    en.alive=false;
    player.vy=-7;
    score+=20;
    addParticles(en.x,en.y,"#ffae53",10);
   }else{
    hurt();
   }
  }
 }

 if(invulnerable>0)invulnerable--;
 for(const p of particles){
  p.x+=p.vx;p.y+=p.vy;p.vy+=.12;p.life--;
 }
 particles=particles.filter(p=>p.life>0);

 camera=Math.max(0,Math.min(worldWidth-W,player.x-W*.34));

 if(player.x+player.w>=worldWidth-90)finishLevel();
 updateHud();
}

function drawBackground(){
 let g=ctx.createLinearGradient(0,0,0,H);
 g.addColorStop(0,"#092d4a");
 g.addColorStop(.5,"#167b78");
 g.addColorStop(1,"#a3c66b");
 ctx.fillStyle=g;ctx.fillRect(0,0,W,H);

 let sun=ctx.createRadialGradient(760,95,5,760,95,125);
 sun.addColorStop(0,"#fff8bb");
 sun.addColorStop(.35,"#ffdc7c88");
 sun.addColorStop(1,"#ffdf7000");
 ctx.fillStyle=sun;ctx.fillRect(600,0,320,240);
 ctx.fillStyle="#fff3a5";
 ctx.beginPath();ctx.arc(760,95,27,0,Math.PI*2);ctx.fill();

 for(let layer=0;layer<3;layer++){
  ctx.beginPath();ctx.moveTo(0,H);
  for(let x=-20;x<=W+40;x+=40){
   const y=220+layer*55+
    Math.sin((x+camera*.12+layer*90)*.012)*32+
    Math.sin(x*.035)*12;
   ctx.lineTo(x,y);
  }
  ctx.lineTo(W,H);ctx.closePath();
  ctx.fillStyle=["#346b65","#24564a","#183f32"][layer];
  ctx.fill();
 }

 for(let i=0;i<24;i++){
  const x=((i*97-camera*.22)%(W+120)+W+120)%(W+120)-60;
  const h=90+(i*37%100);
  ctx.fillStyle=i%2?"#123e2b":"#0d3325";
  ctx.fillRect(x,350-h*.25,12,h);
  for(let j=0;j<4;j++){
   ctx.beginPath();
   ctx.ellipse(x+6,350-h*.25+j*17,27-j*3,30-j*3,0,0,Math.PI*2);
   ctx.fill();
  }
 }
}

function drawPit(p){
 const x=p.x-camera;
 if(x+p.w<0||x>W)return;
 ctx.fillStyle="#07110e";ctx.fillRect(x,p.y,p.w,H-p.y);

 if(p.type==="water"){
  let water=ctx.createLinearGradient(0,p.y,0,H);
  water.addColorStop(0,"#45e6ff");
  water.addColorStop(.35,"#087ec3");
  water.addColorStop(1,"#031b54");
  ctx.fillStyle=water;ctx.fillRect(x,p.y,p.w,H-p.y);
  ctx.save();
  ctx.beginPath();ctx.rect(x,p.y,p.w,H-p.y);ctx.clip();
  for(let i=0;i<5;i++){
   ctx.beginPath();
   ctx.ellipse(x+p.w/2+Math.sin(frame*.045+i)*p.w*.22,
    p.y+12+i*28,p.w*.32,3,0,0,Math.PI*2);
   ctx.strokeStyle="#b9fbff99";ctx.lineWidth=2;ctx.stroke();
  }
  ctx.restore();
  ctx.fillStyle="#bafaff";ctx.fillRect(x,p.y,p.w,3);
 }else if(p.type==="lava"){
  let lava=ctx.createLinearGradient(0,p.y,0,H);
  lava.addColorStop(0,"#ffec4a");
  lava.addColorStop(.22,"#ff6a00");
  lava.addColorStop(1,"#9b0800");
  ctx.fillStyle=lava;ctx.fillRect(x,p.y,p.w,H-p.y);
  ctx.save();
  ctx.beginPath();ctx.rect(x,p.y,p.w,H-p.y);ctx.clip();
  for(let i=0;i<8;i++){
   const bx=x+((i*37+frame*1.5)%(p.w+20))-10;
   const by=p.y+8+Math.abs(Math.sin(frame*.06+i))*40;
   ctx.fillStyle=i%2?"#fff176":"#ff3c00";
   ctx.beginPath();
   ctx.ellipse(bx,by,4+Math.sin(frame*.1+i)*2,3,0,0,Math.PI*2);
   ctx.fill();
  }
  ctx.restore();
  ctx.fillStyle="#fff27b";ctx.fillRect(x,p.y,p.w,4);
 }else{
  ctx.fillStyle="#17120e";ctx.fillRect(x,p.y,p.w,H-p.y);
 }
}

function drawPlatform(p){
 const x=p.x-camera;
 if(x+p.w<0||x>W)return;
 if(p.floating){
  ctx.fillStyle="#432a17";ctx.fillRect(x,p.y,p.w,p.h);
  ctx.fillStyle="#76c63f";ctx.fillRect(x,p.y,p.w,5);
  ctx.fillStyle="#b5e979";ctx.fillRect(x,p.y,p.w,2);
  return;
 }
 let soil=ctx.createLinearGradient(0,p.y,0,p.y+p.h);
 soil.addColorStop(0,"#76502a");
 soil.addColorStop(.18,"#4b321f");
 soil.addColorStop(1,"#1b2519");
 ctx.fillStyle=soil;ctx.fillRect(x,p.y,p.w,p.h);
 ctx.fillStyle="#58a832";ctx.fillRect(x,p.y,p.w,10);
 ctx.fillStyle="#b3e96b";ctx.fillRect(x,p.y,p.w,3);

 for(let i=0;i<p.w;i+=13){
  ctx.fillStyle=i%2?"#397f29":"#8acb44";
  ctx.beginPath();
  ctx.moveTo(x+i,p.y+7);
  ctx.lineTo(x+i+3,p.y-3-(i%4));
  ctx.lineTo(x+i+5,p.y+7);
  ctx.fill();
 }
 for(let i=0;i<p.w;i+=29){
  ctx.fillStyle="#98734b";ctx.fillRect(x+i,p.y+22+(i%27),4,3);
  ctx.fillStyle="#2b271b";ctx.fillRect(x+i+12,p.y+47+(i%20),7,3);
 }
}

function drawPlayer(){
 const x=player.x-camera,y=player.y;
 if(invulnerable>0&&Math.floor(frame/5)%2===0)return;
 ctx.save();
 ctx.fillStyle="#06130b99";
 ctx.beginPath();ctx.ellipse(x+16,y+player.h+3,19,5,0,0,Math.PI*2);ctx.fill();

 ctx.fillStyle="#252f3c";
 ctx.fillRect(x+5,y+player.h-14,9,14);
 ctx.fillRect(x+19,y+player.h-14,9,14);
 ctx.fillStyle="#151b23";
 ctx.fillRect(x+3,y+player.h-5,12,5);
 ctx.fillRect(x+18,y+player.h-5,13,5);

 let body=ctx.createLinearGradient(x,y,x+player.w,y);
 body.addColorStop(0,"#166b45");
 body.addColorStop(.5,"#39bd6c");
 body.addColorStop(1,"#125638");
 ctx.fillStyle=body;ctx.fillRect(x+3,y+15,26,player.h-28);

 ctx.fillStyle="#dca66f";
 ctx.fillRect(x,y+19,7,19);
 ctx.fillRect(x+25,y+19,7,19);
 ctx.fillRect(x+6,y+1,21,20);

 ctx.fillStyle="#1d2924";ctx.fillRect(x+3,y,27,7);
 ctx.fillStyle="#0a1712";ctx.fillRect(x+7,y-3,19,5);
 ctx.fillStyle="#fff";
 ctx.fillRect(x+(player.face===1?20:8),y+8,5,4);
 ctx.fillStyle="#111";
 ctx.fillRect(x+(player.face===1?23:9),y+9,2,3);
 ctx.fillStyle="#e2d49a";
 ctx.fillRect(x+4,y+player.h-17,24,4);

 if(player.attackTime>0){
  ctx.strokeStyle="#e7f6ff";ctx.lineWidth=5;
  ctx.beginPath();
  ctx.moveTo(x+16,y+27);
  ctx.lineTo(x+16+player.face*40,y+8);
  ctx.stroke();
  ctx.strokeStyle="#70edff";ctx.lineWidth=2;
  ctx.beginPath();ctx.arc(x+16+player.face*25,y+18,18,-1.1,1.1);ctx.stroke();
 }
 ctx.restore();
}

function drawCoin(c){
 const x=c.x-camera;
 if(c.taken||x<-20||x>W+20)return;
 let glow=ctx.createRadialGradient(x,c.y,2,x,c.y,24);
 glow.addColorStop(0,"#fffbc9");
 glow.addColorStop(.3,"#ffdf32aa");
 glow.addColorStop(1,"#ffdf3200");
 ctx.fillStyle=glow;ctx.beginPath();ctx.arc(x,c.y,24,0,Math.PI*2);ctx.fill();
 ctx.fillStyle="#ffcf16";
 ctx.beginPath();ctx.ellipse(x,c.y,8,11,0,0,Math.PI*2);ctx.fill();
 ctx.strokeStyle="#fff29b";ctx.lineWidth=2;ctx.stroke();
 ctx.fillStyle="#fff6ba";ctx.fillRect(x-2,c.y-6,3,12);
}

function drawEnemy(en){
 if(!en.alive)return;
 const x=en.x-camera,y=en.y;
 if(x<-40||x>W+40)return;
 ctx.fillStyle="#111c13";ctx.fillRect(x+3,y+12,25,26);
 ctx.fillStyle="#8c342b";ctx.fillRect(x+2,y+6,27,20);
 ctx.fillStyle="#b9533d";ctx.fillRect(x+5,y+1,20,15);
 ctx.fillStyle="#ffe3aa";
 ctx.fillRect(x+6,y+8,5,4);ctx.fillRect(x+18,y+8,5,4);
 ctx.fillStyle="#111";
 ctx.fillRect(x+8,y+9,3,3);ctx.fillRect(x+20,y+9,3,3);
 ctx.fillStyle="#25251e";
 ctx.fillRect(x+3,y+35,10,5);ctx.fillRect(x+18,y+35,10,5);
}

function drawFinish(){
 const x=worldWidth-90-camera;
 if(x<-80||x>W+80)return;
 ctx.fillStyle="#d8e6d8";
 ctx.fillRect(x,310,8,130);
 ctx.fillRect(x+70,310,8,130);
 ctx.fillRect(x,310,78,8);
 for(let r=0;r<5;r++)for(let c=0;c<3;c++){
  ctx.fillStyle=(r+c)%2?"#f6f6e5":"#18221b";
  ctx.fillRect(x+8+c*21,322+r*22,21,22);
 }
 ctx.fillStyle="#fff";ctx.font="bold 16px Arial";
 ctx.fillText("FINISH",x-2,300);
}

function drawParticles(){
 for(const p of particles){
  ctx.globalAlpha=Math.max(0,p.life/40);
  ctx.fillStyle=p.color;
  ctx.beginPath();ctx.arc(p.x-camera,p.y,3,0,Math.PI*2);ctx.fill();
 }
 ctx.globalAlpha=1;
}

function draw(){
 drawBackground();
 for(const p of pits)drawPit(p);
 for(const p of platforms)drawPlatform(p);

 for(const p of pits){
  const x=p.x-camera;
  if(x+p.w<0||x>W)continue;
  if(p.type==="water"){
   ctx.fillStyle="#fff";ctx.font="bold 12px Arial";ctx.textAlign="center";
   ctx.fillText("DEEP WATER",x+p.w/2,Math.min(H-20,p.y+45));
  }else if(p.type==="lava"){
   ctx.fillStyle="#fff4a1";ctx.font="bold 12px Arial";ctx.textAlign="center";
   ctx.fillText("HOT LAVA",x+p.w/2,Math.min(H-20,p.y+45));
  }
 }
 coinItems.forEach(drawCoin);
 enemies.forEach(drawEnemy);
 drawFinish();
 drawPlayer();
 drawParticles();

 ctx.fillStyle="#07150d99";ctx.fillRect(W/2-120,10,240,7);
 ctx.fillStyle="#baff78";
 ctx.fillRect(W/2-120,10,240*Math.min(1,player.x/(worldWidth-90)),7);
}

function loop(){
 update();
 draw();
 requestAnimationFrame(loop);
}

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

Game Source: Jungle Battle Ground

Creator: WildDragon12

Libraries: none

Complexity: complex (746 lines, 20.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: jungle-battle-ground-wilddragon12-mvm6eld8" to link back to the original. Then publish at arcadelab.ai/publish.