🎮ArcadeLab

CAR RACER 3D

by BoldRider35
550 lines14.0 KB
▶ Play
ArcadeLab
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CAR RACER 3D</title>
<style>
*{box-sizing:border-box}
body{
 margin:0;background:#07111e;color:white;
 font-family:Arial,sans-serif;text-align:center;
}
header{
 padding:18px 8px;
 background:linear-gradient(110deg,#06152a,#123e61,#06152a);
 border-bottom:2px solid #21d4fd;
}
h1{margin:0;color:#38e8ff;font-size:30px}
header p{margin:7px 0 0;color:#d9f7ff}
#menu{padding:14px}
.panel{
 max-width:600px;margin:12px auto;padding:15px;
 background:#101f32;border:1px solid #294b67;
 border-radius:16px;
}
.stats{
 display:grid;grid-template-columns:repeat(3,1fr);gap:8px;
}
.stat{background:#071421;border-radius:10px;padding:10px 3px}
.stat b{display:block;color:#42e8ff;font-size:20px;margin-top:5px}
button,select{
 border:0;border-radius:10px;padding:12px;
 font-size:15px;font-weight:bold;cursor:pointer;
}
button{background:#16cce8;color:#04111d;margin:4px}
button:active{transform:scale(.96)}
.secondary{background:#28445f;color:white}
#gameArea{
 display:none;max-width:600px;margin:auto;position:relative;
}
canvas{
 display:block;width:100%;height:auto;
 background:#315d36;border-radius:12px;
 touch-action:none;
}
#hud{
 position:absolute;top:8px;left:8px;right:8px;
 display:flex;justify-content:space-between;gap:5px;
 pointer-events:none;
}
.hudBox{
 background:#071421dd;padding:8px;border-radius:8px;
 font-size:12px;font-weight:bold;
}
#controls{
 display:flex;justify-content:center;gap:18px;
 padding:12px;
}
.control{width:85px;height:58px;font-size:25px}
#result{display:none}
#rewardCards{
 display:flex;justify-content:center;gap:9px;flex-wrap:wrap;
}
.reward{
 width:95px;min-height:125px;border:2px solid #f5d36c;
 border-radius:13px;padding:12px 4px;
 background:linear-gradient(#243d64,#11182d);
}
.reward strong{display:block;font-size:24px;color:#ffdf78;margin:10px 0}
small{color:#bcd3e4}
.hidden{display:none!important}
</style>
</head>
<body>

<header>
 <h1>🏎️ CAR RACER 3D</h1>
 <p>Race • Win • Collect Reward Cards</p>
</header>

<section id="menu">
 <div class="panel">
  <h2>🏆 RACING GARAGE</h2>
  <div class="stats">
   <div class="stat">Coins<b id="coins">0</b></div>
   <div class="stat">Wins<b id="wins">0</b></div>
   <div class="stat">Best<b id="best">0</b></div>
  </div>
  <p>Choose Your Racing Car</p>
  <select id="carChoice">
   <option value="0">🔥 Red Supercar</option>
   <option value="1">⚡ Blue Speedster</option>
   <option value="2">💚 Green Racer</option>
   <option value="3">💜 Purple Phantom</option>
   <option value="4">🖤 Black Shadow</option>
  </select>
  <p><small>Choose your car, then start the championship!</small></p>
  <button onclick="startRace()">🏁 START RACE</button>
  <button class="secondary" onclick="showGarage()">🚘 MY GARAGE</button>
 </div>

 <div class="panel">
  <h3>🎮 HOW TO PLAY</h3>
  <p>Move left and right to avoid opponent cars.</p>
  <p>Survive until the finish line and aim for first place.</p>
  <p>Win first place to unlock three reward cards.</p>
  <small>Dollar values are demo rewards, not real cash.</small>
 </div>
</section>

<section id="gameArea">
 <div id="hud">
  <div class="hudBox">SPEED <span id="speed">0</span></div>
  <div class="hudBox">DISTANCE <span id="distance">0</span> m</div>
  <div class="hudBox">POSITION <span id="position">1</span></div>
 </div>
 <canvas id="canvas" width="480" height="720"></canvas>
 <div id="controls">
  <button class="control" id="left">⬅️</button>
  <button class="control" id="right">➡️</button>
  <button class="control" id="brake">🛑</button>
 </div>
 <button class="secondary" onclick="quitRace()">QUIT RACE</button>
</section>

<section id="result" class="panel">
 <h2 id="resultTitle">🏁 RACE COMPLETE</h2>
 <p id="resultText"></p>
 <div id="rewardCards"></div>
 <p id="cashDisplay">Demo reward balance: $0</p>
 <button onclick="claimCards()">🎁 CLAIM CARDS</button>
 <button class="secondary" onclick="startRace()">🔄 RACE AGAIN</button>
 <button class="secondary" onclick="goHome()">🏠 HOME</button>
 <small>Demo-only balance. No real-money withdrawal is available.</small>
</section>

<section id="garage" class="panel hidden">
 <h2>🚘 YOUR GARAGE</h2>
 <p>Red Supercar • Blue Speedster • Green Racer • Purple Phantom • Black Shadow</p>
 <p>Every car is available in this demo.</p>
 <button onclick="closeGarage()">BACK TO MENU</button>
</section>

<script>
"use strict";

const canvas=document.getElementById("canvas");
const ctx=canvas.getContext("2d");

const colors=["#ff3d55","#28b9ff","#37f58a","#bd75ff","#252b38"];
const carNames=["Red Supercar","Blue Speedster","Green Racer",
"Purple Phantom","Black Shadow"];

let player={x:240,y:575,w:48,h:85};
let opponents=[];
let particles=[];
let roadOffset=0;
let distance=0;
let speed=0;
let raceActive=false;
let animationId=0;
let lastTime=0;
let totalWins=0;
let totalCoins=0;
let bestDistance=0;
let raceNumber=0;
let selectedCar=0;
let claimed=false;
let finished=false;
let cards=[];
let keys={left:false,right:false,brake:false};

const laneCenters=[125,240,355];

function saveStats(){
 try{
  localStorage.setItem("cr3d_stats",JSON.stringify({
   wins:totalWins,coins:totalCoins,best:bestDistance
  }));
 }catch(e){}
}

function loadStats(){
 try{
  const s=JSON.parse(localStorage.getItem("cr3d_stats")||"{}");
  totalWins=Number(s.wins)||0;
  totalCoins=Number(s.coins)||0;
  bestDistance=Number(s.best)||0;
 }catch(e){}
 updateStats();
}

function updateStats(){
 document.getElementById("coins").textContent=totalCoins;
 document.getElementById("wins").textContent=totalWins;
 document.getElementById("best").textContent=bestDistance;
}

function startRace(){
 cancelAnimationFrame(animationId);
 selectedCar=Number(document.getElementById("carChoice").value)||0;
 player={x:240,y:575,w:48,h:85};
 opponents=[];
 particles=[];
 distance=0;
 speed=0;
 roadOffset=0;
 raceNumber++;
 claimed=false;
 finished=false;
 lastTime=0;
 keys={left:false,right:false,brake:false};

 // Three lanes of computer-controlled opponents.
 for(let i=0;i<8;i++){
  const lane=i%3;
  opponents.push({
   x:laneCenters[lane],
   y:-150-i*175,
   w:44,h:78,
   lane:lane,
   color:colors[(i+1)%colors.length],
   speed:0.7+Math.random()*1.0,
   passed:false
  });
 }

 document.getElementById("menu").style.display="none";
 document.getElementById("garage").classList.add("hidden");
 document.getElementById("result").style.display="none";
 document.getElementById("gameArea").style.display="block";
 raceActive=true;
 animationId=requestAnimationFrame(loop);
}

function drawCar(x,y,w,h,color,isPlayer=false){
 ctx.save();
 ctx.translate(x,y);

 // Shadow
 ctx.fillStyle="#0006";
 ctx.fillRect(-w/2+4,5,w,h);

 // Wheels
 ctx.fillStyle="#111";
 ctx.fillRect(-w/2-4,h*.17,7,h*.23);
 ctx.fillRect(w/2-3,h*.17,7,h*.23);
 ctx.fillRect(-w/2-4,h*.65,7,h*.23);
 ctx.fillRect(w/2-3,h*.65,7,h*.23);

 // Body
 ctx.fillStyle=color;
 ctx.beginPath();
 ctx.moveTo(-w*.38,h);
 ctx.lineTo(-w*.48,h*.24);
 ctx.quadraticCurveTo(-w*.47,h*.05,-w*.23,0);
 ctx.lineTo(w*.23,0);
 ctx.quadraticCurveTo(w*.47,h*.05,w*.48,h*.24);
 ctx.lineTo(w*.38,h);
 ctx.closePath();
 ctx.fill();

 // Windows
 ctx.fillStyle="#b9efff";
 ctx.beginPath();
 ctx.moveTo(-w*.29,h*.27);
 ctx.lineTo(-w*.21,h*.12);
 ctx.lineTo(w*.21,h*.12);
 ctx.lineTo(w*.29,h*.27);
 ctx.closePath();
 ctx.fill();

 ctx.fillStyle="#19344b";
 ctx.fillRect(-w*.29,h*.43,w*.58,h*.22);

 // Headlights
 ctx.fillStyle="#fff7a0";
 ctx.fillRect(-w*.36,h*.07,w*.19,5);
 ctx.fillRect(w*.17,h*.07,w*.19,5);

 // Tail lights
 ctx.fillStyle="#ff3030";
 ctx.fillRect(-w*.35,h*.88,w*.19,5);
 ctx.fillRect(w*.16,h*.88,w*.19,5);

 if(isPlayer){
  ctx.strokeStyle="#ffffff";
  ctx.lineWidth=2;
  ctx.strokeRect(-w*.5,-1,w,h+2);
 }
 ctx.restore();
}

function drawRoad(){
 const w=canvas.width,h=canvas.height;
 ctx.fillStyle="#285a34";
 ctx.fillRect(0,0,w,h);

 // Road edges
 ctx.fillStyle="#b5b9bd";
 ctx.fillRect(52,0,376,h);

 ctx.fillStyle="#30353d";
 ctx.fillRect(62,0,356,h);

 // Road markings
 ctx.fillStyle="#f5f5f5";
 const dash=55,gap=40;
 for(let y=-dash;y<h+dash;y+=dash+gap){
  let yy=(y+roadOffset)%(dash+gap);
  if(yy<0)yy+=dash+gap;
  ctx.fillRect(178,yy,5,dash);
  ctx.fillRect(297,yy,5,dash);
 }

 // Grass stripes
 ctx.fillStyle="#367746";
 for(let y=-80;y<h+80;y+=80){
  let yy=(y+roadOffset*1.2)% (h+80);
  ctx.fillRect(0,yy,49,18);
  ctx.fillRect(431,yy,49,18);
 }
}

function rectsCollide(a,b){
 return a.x-a.w/2 < b.x+b.w/2 &&
 a.x+a.w/2 > b.x-b.w/2 &&
 a.y < b.y+b.h &&
 a.y+a.h > b.y;
}

function spawnParticles(x,y){
 for(let i=0;i<10;i++){
  particles.push({
   x:x+(Math.random()-.5)*25,
   y:y,
   vx:(Math.random()-.5)*3,
   vy:-Math.random()*3,
   life:1
  });
 }
}

function update(dt){
 const scale=Math.min(dt/16.67,2);
 const acceleration=keys.brake?0.12:0.48;
 speed+=(acceleration-speed)*0.035*scale;
 speed=Math.max(0,Math.min(speed,180));

 if(keys.left)player.x-=4.7*scale;
 if(keys.right)player.x+=4.7*scale;
 player.x=Math.max(91,Math.min(389,player.x));

 roadOffset=(roadOffset+speed*.65*scale)%95;
 distance+=speed*.018*scale;

 opponents.forEach(car=>{
  car.y+=((speed*.50)+car.speed*1.6)*scale;
  if(car.y>canvas.height+100){
   car.y=-100-Math.random()*160;
   car.lane=Math.floor(Math.random()*3);
   car.x=laneCenters[car.lane];
   car.color=colors[Math.floor(Math.random()*colors.length)];
   car.passed=false;
  }

  if(rectsCollide(player,car)){
   speed*=0.65;
   spawnParticles(player.x,player.y+20);
   car.y=-150-Math.random()*150;
  }
 });

 particles=particles.filter(p=>p.life>0);
 particles.forEach(p=>{
  p.x+=p.vx*scale;
  p.y+=p.vy*scale;
  p.life-=0.025*scale;
 });

 // The finish line comes after a fixed race distance.
 if(distance>=1000&&!finished){
  finishRace();
 }
}

function draw(){
 drawRoad();

 opponents.forEach(car=>{
  drawCar(car.x,car.y,car.w,car.h,car.color);
 });

 drawCar(player.x,player.y,player.w,player.h,colors[selectedCar],true);

 particles.forEach(p=>{
  ctx.globalAlpha=Math.max(0,p.life);
  ctx.fillStyle="#ffcb60";
  ctx.fillRect(p.x,p.y,4,4);
 });
 ctx.globalAlpha=1;

 // Finish distance bar
 ctx.fillStyle="#071421";
 ctx.fillRect(90,12,300,7);
 ctx.fillStyle="#22e4ff";
 ctx.fillRect(90,12,300*Math.min(distance/1000,1),7);
}

function loop(time){
 if(!raceActive)return;
 if(!lastTime)lastTime=time;
 const dt=Math.min(time-lastTime,40);
 lastTime=time;

 update(dt);
 draw();

 document.getElementById("speed").textContent=Math.round(speed);
 document.getElementById("distance").textContent=Math.floor(distance);

 const passed=opponents.filter(c=>c.y>player.y+player.h).length;
 const pos=Math.min(8,Math.max(1,8-passed));
 document.getElementById("position").textContent=pos;

 animationId=requestAnimationFrame(loop);
}

function finishRace(){
 if(finished)return;
 finished=true;
 raceActive=false;
 cancelAnimationFrame(animationId);

 const won=distance>=1000;
 bestDistance=Math.max(bestDistance,Math.floor(distance));

 document.getElementById("gameArea").style.display="none";
 document.getElementById("result").style.display="block";
 document.getElementById("rewardCards").innerHTML="";

 if(won){
  totalWins++;
  cards=[
   {name:"CARD ONE",amount:1},
   {name:"CARD TWO",amount:1},
   {name:"CARD THREE",amount:1}
  ];
  document.getElementById("resultTitle").textContent="🏆 FINISH LINE REACHED!";
  document.getElementById("resultText").textContent=
   "Amazing race! You reached the finish line. Claim your three demo reward cards.";
  cards.forEach((card,i)=>{
   const el=document.createElement("div");
   el.className="reward";
   el.innerHTML="🃏<br>"+card.name+
   "<strong>$"+card.amount+"</strong><small>DEMO VALUE</small>";
   document.getElementById("rewardCards").appendChild(el);
  });
 }else{
  cards=[];
  document.getElementById("resultTitle").textContent="🏁 RACE ENDED";
  document.getElementById("resultText").textContent=
   "Keep practicing and try again!";
 }

 document.getElementById("cashDisplay").textContent=
 "Demo reward balance: $"+totalCoins;
 saveStats();
 updateStats();
}

function claimCards(){
 if(claimed||cards.length===0)return;
 claimed=true;

 // Demo coins only: no cash payment or withdrawal.
 totalCoins+=cards.reduce((sum,c)=>sum+c.amount,0);
 cards=[];
 document.getElementById("rewardCards").innerHTML=
 "<p>✅ Demo cards claimed! Your demo balance has been updated.</p>";
 document.getElementById("cashDisplay").textContent=
 "Demo reward balance: $"+totalCoins;
 saveStats();
 updateStats();
}

function quitRace(){
 raceActive=false;
 cancelAnimationFrame(animationId);
 goHome();
}

function goHome(){
 raceActive=false;
 cancelAnimationFrame(animationId);
 document.getElementById("result").style.display="none";
 document.getElementById("gameArea").style.display="none";
 document.getElementById("menu").style.display="block";
}

function showGarage(){
 document.getElementById("menu").style.display="none";
 document.getElementById("garage").classList.remove("hidden");
}

function closeGarage(){
 document.getElementById("garage").classList.add("hidden");
 document.getElementById("menu").style.display="block";
}

// Keyboard support
window.addEventListener("keydown",e=>{
 if(["ArrowLeft","ArrowRight"," ","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")keys.brake=true;
});

window.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")keys.brake=false;
});

// Mobile touch controls
function bindHold(id,key){
 const el=document.getElementById(id);
 el.addEventListener("pointerdown",e=>{
  e.preventDefault();
  keys[key]=true;
  el.setPointerCapture(e.pointerId);
 });
 const release=e=>{
  e.preventDefault();
  keys[key]=false;
 };
 el.addEventListener("pointerup",release);
 el.addEventListener("pointercancel",release);
 el.addEventListener("lostpointercapture",()=>keys[key]=false);
}
bindHold("left","left");
bindHold("right","right");
bindHold("brake","brake");

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

Game Source: CAR RACER 3D

Creator: BoldRider35

Libraries: none

Complexity: complex (550 lines, 14.0 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: car-racer-3d-boldrider35-mv3izy9r" to link back to the original. Then publish at arcadelab.ai/publish.