NEON RUSH
by FrozenOwl79414 lines11.0 KB
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>NEON RUSH</title>
<style>
*{box-sizing:border-box}
html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#050510;font-family:Arial;color:white}
canvas{display:block;width:100%;height:100%;touch-action:none}
#hud{position:fixed;top:12px;left:12px;right:12px;display:flex;justify-content:space-between;pointer-events:none;font-weight:bold;text-shadow:0 0 8px #00eaff}
.panel{background:#071022aa;border:1px solid #00d9ff66;border-radius:12px;padding:7px 10px}
#menu{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:radial-gradient(circle,#10194d,#03030b 70%);text-align:center}
.box{width:min(90%,430px);padding:28px;border:1px solid #00eaff88;border-radius:24px;background:#071022dd;box-shadow:0 0 50px #0077ff55}
h1{font-size:52px;margin:0;color:#00eaff;text-shadow:0 0 15px #00eaff,0 0 35px #7b00ff}
h2{color:#ff28d7}
button{border:0;border-radius:14px;padding:14px 22px;margin:6px;background:#086dff;color:white;font-size:17px;font-weight:bold;box-shadow:0 0 15px #0077ff88}
button:active{transform:scale(.95)}
#controls{position:fixed;bottom:18px;left:0;right:0;display:flex;justify-content:space-between;padding:0 22px;pointer-events:none}
.ctrl{pointer-events:auto;width:72px;height:72px;border-radius:50%;background:#071a32aa;border:2px solid #00d9ff88;color:white;font-size:28px}
.nitro{border-color:#ff20d0;color:#ff20d0;width:90px;height:90px}
#gameover{display:none;position:fixed;inset:0;background:#03030ddd;align-items:center;justify-content:center;text-align:center}
.stat{font-size:19px;margin:10px}
</style>
</head>
<body>
<canvas id="game"></canvas>
<div id="hud">
<div class="panel">🏁 <span id="score">0</span></div>
<div class="panel">💎 <span id="coins">0</span></div>
<div class="panel">⚡ <span id="nitro">100</span>%</div>
<div class="panel">LV <span id="level">1</span></div>
</div>
<div id="menu">
<div class="box">
<h1>NEON<br>RUSH</h1>
<p>HIGH SPEED • NEON CITY • POLICE CHASE</p>
<button onclick="startGame()">START RUSH</button>
<button onclick="upgrade()">UPGRADE CAR</button>
<div id="up">Speed Lv 1 • Handling Lv 1 • Nitro Lv 1</div>
<p>Best: <span id="best">0</span></p>
</div>
</div>
<div id="controls">
<div>
<button class="ctrl" id="left">◀</button>
<button class="ctrl" id="right">▶</button>
</div>
<button class="ctrl nitro" id="boost">⚡</button>
</div>
<div id="gameover">
<div class="box">
<h2>CRASHED</h2>
<div class="stat">Score: <b id="finalScore">0</b></div>
<div class="stat">Coins: <b id="finalCoins">0</b></div>
<button onclick="startGame()">RACE AGAIN</button>
<button onclick="backMenu()">MENU</button>
</div>
</div>
<script>
const c=document.getElementById("game");
const ctx=c.getContext("2d");
let W,H,DPR;
function resize(){
DPR=Math.min(devicePixelRatio||1,2);
W=innerWidth;H=innerHeight;
c.width=W*DPR;c.height=H*DPR;
ctx.setTransform(DPR,0,0,DPR,0,0);
}
addEventListener("resize",resize);resize();
let running=false;
let score=0,coins=0,nitro=100,level=1;
let speed=7,roadY=0,spawn=0,coinSpawn=0;
let player={x:0,y:0,w:44,h:78,tilt:0};
let cars=[],gems=[],particles=[];
let keys={left:false,right:false,boost:false};
let high=+localStorage.neonHigh||0;
let upgrades=JSON.parse(localStorage.neonUp||'{"speed":1,"handling":1,"nitro":1}');
function updateUp(){
document.getElementById("up").textContent=
"Speed Lv "+upgrades.speed+" • Handling Lv "+upgrades.handling+
" • Nitro Lv "+upgrades.nitro;
}
updateUp();
document.getElementById("best").textContent=high;
function upgrade(){
let cost=500*upgrades.speed+500*upgrades.handling+500*upgrades.nitro;
if((+localStorage.neonCoins||0)<cost){
alert("Need "+cost+" coins from races.");
return;
}
localStorage.neonCoins=(+localStorage.neonCoins||0)-cost;
upgrades.speed++;upgrades.handling++;upgrades.nitro++;
localStorage.neonUp=JSON.stringify(upgrades);
updateUp();
}
function startGame(){
document.getElementById("menu").style.display="none";
document.getElementById("gameover").style.display="none";
running=true;
score=0;coins=0;nitro=100;level=1;
speed=7+upgrades.speed*.45;
roadY=0;spawn=0;coinSpawn=0;
cars=[];gems=[];particles=[];
player.x=W/2;player.y=H-145;
requestAnimationFrame(loop);
}
function backMenu(){
running=false;
document.getElementById("gameover").style.display="none";
document.getElementById("menu").style.display="flex";
}
function road(){
let rw=Math.min(W*.72,520);
let left=(W-rw)/2;
return {left,right:left+rw,w:rw};
}
function drawCity(){
let r=road();
let g=ctx.createLinearGradient(0,0,0,H);
g.addColorStop(0,"#05051a");
g.addColorStop(1,"#151035");
ctx.fillStyle=g;ctx.fillRect(0,0,W,H);
// buildings
for(let side=0;side<2;side++){
let start=side? r.right+5:0;
let end=side?W:r.left-5;
let bw=42;
for(let x=start;x<end;x+=bw+7){
let seed=Math.floor(x/49);
let bh=90+(Math.abs(seed*37)%170);
ctx.fillStyle=side?"#101338":"#0d1230";
ctx.fillRect(x,H-bh,bw,bh);
for(let y=H-bh+12;y<H-10;y+=20){
if((Math.floor(y/20)+seed)%3){
ctx.fillStyle=(seed%2)?"#00eaff":"#ff20d0";
ctx.globalAlpha=.45;
ctx.fillRect(x+8,y,6,5);
ctx.fillRect(x+24,y,6,5);
ctx.globalAlpha=1;
}
}
}
}
// road
ctx.fillStyle="#080a12";
ctx.fillRect(r.left,0,r.w,H);
// glowing edges
ctx.shadowBlur=15;ctx.shadowColor="#00eaff";
ctx.strokeStyle="#00eaff";ctx.lineWidth=3;
ctx.beginPath();ctx.moveTo(r.left,0);ctx.lineTo(r.left,H);ctx.stroke();
ctx.shadowBlur=15;ctx.shadowColor="#ff20d0";
ctx.strokeStyle="#ff20d0";
ctx.beginPath();ctx.moveTo(r.right,0);ctx.lineTo(r.right,H);ctx.stroke();
ctx.shadowBlur=0;
// lane lines
let lanes=4,lw=r.w/lanes;
for(let i=1;i<lanes;i++){
for(let y=-80+(roadY%120);y<H;y+=120){
ctx.fillStyle="#ffffff55";
ctx.fillRect(r.left+i*lw-2,y,4,65);
}
}
}
function car(x,y,color,police=false,scale=1){
ctx.save();
ctx.translate(x,y);
ctx.shadowBlur=18;ctx.shadowColor=color;
let w=44*scale,h=78*scale;
ctx.fillStyle=color;
ctx.beginPath();
ctx.roundRect(-w/2,-h/2,w,h,9);
ctx.fill();
ctx.shadowBlur=0;
ctx.fillStyle="#07101e";
ctx.beginPath();
ctx.roundRect(-w*.32,-h*.32,w*.64,h*.28,5);
ctx.fill();
ctx.beginPath();
ctx.roundRect(-w*.32,h*.04,w*.64,h*.22,5);
ctx.fill();
ctx.fillStyle="#ddd";
ctx.fillRect(-w*.43,-h*.36,5,11);
ctx.fillRect(w*.32,-h*.36,5,11);
ctx.fillStyle="#ff1744";
ctx.fillRect(-w*.38,h*.30,7,7);
ctx.fillRect(w*.22,h*.30,7,7);
if(police){
ctx.fillStyle="#fff";
ctx.fillRect(-w*.16,-h*.48,w*.32,7);
ctx.fillStyle="#00eaff";
ctx.fillRect(-w*.16,-h*.48,w*.16,7);
ctx.fillStyle="#ff1744";
ctx.fillRect(0,-h*.48,w*.16,7);
}
ctx.restore();
}
function coin(x,y){
ctx.save();
ctx.translate(x,y);
ctx.rotate(performance.now()/500);
ctx.shadowBlur=15;ctx.shadowColor="#ffe600";
ctx.fillStyle="#ffe600";
ctx.beginPath();ctx.arc(0,0,12,0,Math.PI*2);ctx.fill();
ctx.fillStyle="#8a5700";
ctx.font="bold 13px Arial";
ctx.textAlign="center";ctx.textBaseline="middle";
ctx.fillText("$",0,1);
ctx.restore();
}
function explosion(x,y){
for(let i=0;i<18;i++){
particles.push({
x,y,
vx:(Math.random()-.5)*8,
vy:(Math.random()-.5)*8,
life:1
});
}
}
function spawnCar(){
let r=road(),lane=Math.floor(Math.random()*4);
let x=r.left+r.w/4*lane+r.w/8;
cars.push({
x,y:-100,
w:44,h:78,
speed:3+Math.random()*4+level*.25,
color:["#ff206e","#7b2cff","#00eaff","#ff8c00","#21ff72"][Math.floor(Math.random()*5)],
police:level>=4&&Math.random()<.15
});
}
function spawnCoin(){
let r=road(),lane=Math.floor(Math.random()*4);
gems.push({
x:r.left+r.w/4*lane+r.w/8,
y:-30,
spin:0
});
}
function hit(a,b){
return Math.abs(a.x-b.x)<(a.w+b.w)/2*.72 &&
Math.abs(a.y-b.y)<(a.h+b.h)/2*.72;
}
function loop(t){
if(!running)return;
ctx.clearRect(0,0,W,H);
roadY+=speed;
drawCity();
// boost
let boosting=keys.boost&&nitro>0;
if(boosting){
speed+=(12+upgrades.speed)-speed*.08;
nitro-=.65;
for(let i=0;i<2;i++)particles.push({
x:player.x+(Math.random()-.5)*20,
y:player.y+45,
vx:(Math.random()-.5)*2,
vy:5+Math.random()*5,
life:1
});
}else{
let target=7+upgrades.speed*.45+level*.12;
speed+=(target-speed)*.03;
nitro=Math.min(100,nitro+.08*upgrades.nitro);
}
// steering
let steer=5+upgrades.handling*.7;
if(keys.left){player.x-=steer;player.tilt=-.12}
else if(keys.right){player.x+=steer;player.tilt=.12}
else player.tilt*=.8;
let r=road();
player.x=Math.max(r.left+25,Math.min(r.right-25,player.x));
// spawn
spawn-=1;
if(spawn<=0){
spawn=Math.max(25,65-level*3);
spawnCar();
}
coinSpawn--;
if(coinSpawn<=0){
coinSpawn=45+Math.random()*55;
spawnCoin();
}
// cars
for(let i=cars.length-1;i>=0;i--){
let a=cars[i];
a.y+=a.speed+speed*.35;
car(a.x,a.y,a.color,a.police);
if(hit(player,a)){
explosion(player.x,player.y);
endGame();
return;
}
if(a.y>H+100)cars.splice(i,1);
}
// coins
for(let i=gems.length-1;i>=0;i--){
let q=gems[i];
q.y+=speed;
coin(q.x,q.y);
if(Math.hypot(q.x-player.x,q.y-player.y)<30){
coins++;
score+=100;
gems.splice(i,1);
for(let n=0;n<6;n++)particles.push({
x:q.x,y:q.y,vx:(Math.random()-.5)*4,vy:(Math.random()-.5)*4,life:1
});
}else if(q.y>H+30)gems.splice(i,1);
}
// player
car(player.x,player.y,"#00eaff",false,1);
// particles
for(let i=particles.length-1;i>=0;i--){
let p=particles[i];
p.x+=p.vx;p.y+=p.vy;p.life-=.035;
ctx.globalAlpha=Math.max(0,p.life);
ctx.fillStyle="#00eaff";
ctx.fillRect(p.x,p.y,4,4);
ctx.globalAlpha=1;
if(p.life<=0)particles.splice(i,1);
}
score+=Math.floor(speed*.08);
level=1+Math.floor(score/2500);
document.getElementById("score").textContent=score;
document.getElementById("coins").textContent=coins;
document.getElementById("nitro").textContent=Math.floor(nitro);
document.getElementById("level").textContent=level;
requestAnimationFrame(loop);
}
function endGame(){
running=false;
localStorage.neonCoins=(+localStorage.neonCoins||0)+coins;
if(score>high){
high=score;
localStorage.neonHigh=high;
}
document.getElementById("finalScore").textContent=score;
document.getElementById("finalCoins").textContent=coins;
document.getElementById("gameover").style.display="flex";
}
function bind(id,key){
let b=document.getElementById(id);
b.addEventListener("pointerdown",e=>{e.preventDefault();keys[key]=true});
b.addEventListener("pointerup",e=>{e.preventDefault();keys[key]=false});
b.addEventListener("pointercancel",()=>keys[key]=false);
b.addEventListener("pointerleave",()=>keys[key]=false);
}
bind("left","left");
bind("right","right");
bind("boost","boost");
addEventListener("keydown",e=>{
if(e.key==="ArrowLeft"||e.key==="a")keys.left=true;
if(e.key==="ArrowRight"||e.key==="d")keys.right=true;
if(e.key===" "||e.key==="Shift")keys.boost=true;
});
addEventListener("keyup",e=>{
if(e.key==="ArrowLeft"||e.key==="a")keys.left=false;
if(e.key==="ArrowRight"||e.key==="d")keys.right=false;
if(e.key===" "||e.key==="Shift")keys.boost=false;
});
</script>
</body>
</html>Game Source: NEON RUSH
Creator: FrozenOwl79
Libraries: none
Complexity: complex (414 lines, 11.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: neon-rush-frozenowl79" to link back to the original. Then publish at arcadelab.ai/publish.