CAR RACER 3D
by BoldRider35550 lines14.0 KB
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.