Scan to open on your phone
Point a camera at the QR code - it opens this exact paste, no app needed.
https://codepastes.com/zzgtasgzeded8n52FunPlain Text
<script>
/* =========================================================
SHARED ARCADE COINS
========================================================= */
let arcadeCoins = Number(localStorage.getItem("arcadeCoins") || 0);
function saveCoins(){
localStorage.setItem("arcadeCoins",Math.floor(arcadeCoins));
}
function addCoins(amount){
arcadeCoins += Math.max(0,Math.floor(amount));
saveCoins();
updateArcadeCoins();
}
function spendCoins(amount){
amount=Math.floor(amount);
if(arcadeCoins<amount)return false;
arcadeCoins-=amount;
saveCoins();
updateArcadeCoins();
return true;
}
function updateArcadeCoins(){
let el=document.getElementById("arcadeCoinDisplay");
if(!el){
el=document.createElement("div");
el.id="arcadeCoinDisplay";
el.style.cssText=`
position:fixed;
top:15px;
right:15px;
z-index:999;
padding:10px 16px;
border-radius:14px;
background:linear-gradient(135deg,#151d37,#0b1022);
border:1px solid #ffd84d66;
color:#fff;
font-weight:bold;
box-shadow:0 8px 30px #0008;
`;
document.body.appendChild(el);
}
el.textContent="๐ช "+Math.floor(arcadeCoins);
}
function coinReward(amount){
addCoins(amount);
const el=document.createElement("div");
el.textContent=`+${Math.floor(amount)} ๐ช`;
el.style.cssText=`
position:fixed;
left:50%;
top:80px;
transform:translateX(-50%);
z-index:1000;
color:#ffd84d;
font-size:22px;
font-weight:bold;
pointer-events:none;
text-shadow:0 0 15px #ffd84d;
animation:coinFloat 1s forwards;
`;
document.body.appendChild(el);
setTimeout(()=>el.remove(),1000);
}
if(!document.getElementById("coinAnimationStyle")){
const style=document.createElement("style");
style.id="coinAnimationStyle";
style.textContent=`
@keyframes coinFloat{
0%{
opacity:0;
transform:translate(-50%,20px) scale(.7);
}
20%{
opacity:1;
}
100%{
opacity:0;
transform:translate(-50%,-60px) scale(1.2);
}
}
`;
document.head.appendChild(style);
}
updateArcadeCoins();
/* =========================================================
CORE
========================================================= */
const modal=document.getElementById("modal");
const gameTitle=document.getElementById("gameTitle");
const gameContent=document.getElementById("gameContent");
const titles={
clicker:"โก Power Clicker",
runner:"๐ Neon Runner",
snake:"๐ Snake Evolution",
target:"๐ฏ Target Rush",
memory:"๐ง Memory Master",
dodge:"โ๏ธ Asteroid Dodge",
brick:"๐งฑ Brick Breaker",
racer:"๐๏ธ Highway Racer"
};
let currentGame=null;
let cleanupGame=null;
document.querySelectorAll(".game-card").forEach(card=>{
card.addEventListener("click",()=>openGame(card.dataset.game));
});
function openGame(name){
if(cleanupGame)cleanupGame();
currentGame=name;
gameTitle.textContent=titles[name];
modal.classList.add("show");
gameContent.innerHTML="";
const games={
clicker:powerClicker,
runner:neonRunner,
snake:snakeEvolution,
target:targetRush,
memory:memoryMaster,
dodge:asteroidDodge,
brick:brickBreaker,
racer:highwayRacer
};
cleanupGame=games[name]();
}
function closeGame(){
if(cleanupGame)cleanupGame();
cleanupGame=null;
currentGame=null;
modal.classList.remove("show");
updateArcadeCoins();
}
modal.addEventListener("click",e=>{
if(e.target===modal)closeGame();
});
function money(n){
return Math.floor(n).toLocaleString();
}
function save(key,value){
localStorage.setItem(key,JSON.stringify(value));
}
function load(key,def){
try{
const v=JSON.parse(localStorage.getItem(key));
return v??def;
}catch{
return def;
}
}
/* =========================================================
POWER CLICKER
========================================================= */
function powerClicker(){
let energy=load("gm_energy",0);
let clickLevel=load("gm_clickLevel",0);
let generator=load("gm_generator",0);
let crit=load("gm_crit",0);
let comboLevel=load("gm_combo",0);
let prestige=load("gm_prestige",0);
let combo=0;
let lastClick=0;
let timer;
gameContent.innerHTML=`
<div class="game-stats">
<div class="game-stat">ENERGY<strong id="pcEnergy">0</strong></div>
<div class="game-stat">PER CLICK<strong id="pcClick">1</strong></div>
<div class="game-stat">PER SECOND<strong id="pcGen">0</strong></div>
<div class="game-stat">COMBO<strong id="pcCombo">0x</strong></div>
<div class="game-stat">PRESTIGE<strong id="pcPrestige">0</strong></div>
</div>
<div class="orb-wrap">
<div class="energy-orb" id="energyOrb">โก</div>
</div>
<div class="notice" id="pcNotice">
Click the energy core!
</div>
<div class="controls">
<button class="btn primary" id="prestigeBtn">
๐ Prestige
</button>
</div>
<div class="upgrades">
<div class="upgrade">
<h3>๐งค Plasma Gloves</h3>
<p>Increase energy earned per click.</p>
<button class="btn" id="pcClickUp"></button>
</div>
<div class="upgrade">
<h3>โ๏ธ Auto Generator</h3>
<p>Creates energy every second.</p>
<button class="btn" id="pcGenUp"></button>
</div>
<div class="upgrade">
<h3>๐ฅ Critical Reactor</h3>
<p>Chance for a massive energy hit.</p>
<button class="btn" id="pcCritUp"></button>
</div>
<div class="upgrade">
<h3>๐ฅ Combo Core</h3>
<p>Rapid clicking increases your multiplier.</p>
<button class="btn" id="pcComboUp"></button>
</div>
</div>
`;
const $=id=>document.getElementById(id);
function clickPower(){
return Math.max(
1,
1+clickLevel*2+prestige*3
);
}
function update(){
$("pcEnergy").textContent=money(energy);
$("pcClick").textContent=
money(clickPower());
$("pcGen").textContent=
money(generator*(prestige+1));
$("pcCombo").textContent=
combo.toFixed(1)+"x";
$("pcPrestige").textContent=prestige;
$("pcClickUp").textContent=
`Upgrade โข ${50+clickLevel*100} โก`;
$("pcGenUp").textContent=
`Upgrade โข ${75+generator*175} โก`;
$("pcCritUp").textContent=
`Upgrade โข ${250+crit*400} โก`;
$("pcComboUp").textContent=
`Upgrade โข ${150+comboLevel*250} โก`;
save("gm_energy",energy);
save("gm_clickLevel",clickLevel);
save("gm_generator",generator);
save("gm_crit",crit);
save("gm_combo",comboLevel);
save("gm_prestige",prestige);
}
function floating(text){
const el=document.createElement("div");
el.className="float-text";
el.textContent=text;
const r=$("energyOrb").getBoundingClientRect();
el.style.left=
(r.left+r.width/2)+"px";
el.style.top=
(r.top+30)+"px";
document.body.appendChild(el);
setTimeout(()=>el.remove(),900);
}
$("energyOrb").onclick=()=>{
const now=Date.now();
if(now-lastClick<900){
combo=Math.min(
10,
combo+.25+comboLevel*.03
);
}else{
combo=1;
}
lastClick=now;
let amount=
clickPower()*combo;
if(Math.random()<crit*.03){
amount*=5;
floating(
"CRITICAL! +"+
Math.floor(amount)
);
/* clicking gives arcade coins too */
addCoins(1);
}else{
floating(
"+"+
Math.floor(amount)
);
}
energy+=amount;
update();
};
$("pcClickUp").onclick=()=>{
const cost=
50+clickLevel*100;
if(energy>=cost){
energy-=cost;
clickLevel++;
update();
}
};
$("pcGenUp").onclick=()=>{
const cost=
75+generator*175;
if(energy>=cost){
energy-=cost;
generator++;
update();
}
};
$("pcCritUp").onclick=()=>{
const cost=
250+crit*400;
if(
energy>=cost &&
crit<15
){
energy-=cost;
crit++;
update();
}
};
$("pcComboUp").onclick=()=>{
const cost=
150+comboLevel*250;
if(energy>=cost){
energy-=cost;
comboLevel++;
update();
}
};
$("prestigeBtn").onclick=()=>{
const needed=
100000*(prestige+1);
if(energy>=needed){
energy=0;
clickLevel=0;
generator=0;
crit=0;
comboLevel=0;
prestige++;
/* Prestige reward */
coinReward(50*prestige);
$("pcNotice").textContent=
"๐ PRESTIGE COMPLETE! +"+
(50*prestige)+
" arcade coins!";
update();
}else{
$("pcNotice").textContent=
`Need ${money(needed)} energy.`;
}
};
timer=setInterval(()=>{
if(generator>0){
energy+=
generator*(prestige+1);
/* passive gameplay reward */
if(Math.random()<.15){
addCoins(1);
}
update();
}
if(
Date.now()-lastClick>1200 &&
combo>0
){
combo=Math.max(
0,
combo-.5
);
update();
}
},1000);
update();
return()=>{
clearInterval(timer);
};
}
/* =========================================================
NEON RUNNER
========================================================= */
function neonRunner(){
gameContent.innerHTML=`
<div class="game-stats">
<div class="game-stat">SCORE<strong id="runScore">0</strong></div>
<div class="game-stat">COINS<strong id="runCoins">0</strong></div>
<div class="game-stat">LIVES<strong id="runLives">3</strong></div>
<div class="game-stat">BEST<strong id="runBest">0</strong></div>
</div>
<canvas id="runnerCanvas"
width="900"
height="420"></canvas>
<div class="touch-controls">
<button id="runLeft">โ</button>
<button id="runJump">โฒ</button>
<button id="runRight">โถ</button>
</div>
<div class="controls">
<button class="btn primary"
id="runStart">
โถ Start / Restart
</button>
</div>
<div class="upgrades">
<div class="upgrade">
<h3>๐ Speed Shoes</h3>
<p>Improve your running speed.</p>
<button class="btn"
id="runSpeedUp">
</button>
</div>
<div class="upgrade">
<h3>๐ชฝ Double Jump</h3>
<p>Unlock a second jump.</p>
<button class="btn"
id="runJumpUp">
</button>
</div>
<div class="upgrade">
<h3>๐ก๏ธ Shield</h3>
<p>Protect yourself from obstacles.</p>
<button class="btn"
id="runShieldUp">
</button>
</div>
<div class="upgrade">
<h3>๐งฒ Coin Magnet</h3>
<p>Pull nearby coins toward you.</p>
<button class="btn"
id="runMagnetUp">
</button>
</div>
</div>
<div class="notice"
id="runNotice">
Press Start!
</div>
`;
const canvas=
document.getElementById("runnerCanvas");
const ctx=
canvas.getContext("2d");
let speedLevel=
load("run_speed",0);
let jumpLevel=
load("run_jump",0);
let shieldLevel=
load("run_shield",0);
let magnetLevel=
load("run_magnet",0);
let best=
load("run_best",0);
let score=0;
let coins=0;
let lives=3;
let running=false;
let frame=0;
let raf;
let player;
let obstacles;
let coinList;
function reset(){
score=0;
coins=0;
lives=
3+shieldLevel;
frame=0;
player={
x:120,
y:310,
w:35,
h:55,
vy:0,
onGround:true,
jumps:0,
shield:shieldLevel
};
obstacles=[];
coinList=[];
running=true;
loop();
}
function jump(){
if(!running)return;
if(player.onGround){
player.vy=-14;
player.onGround=false;
player.jumps=1;
}else if(
jumpLevel>0 &&
player.jumps<2
){
player.vy=-13;
player.jumps++;
}
}
function update(){
frame++;
score+=.1;
const worldSpeed=
6+
speedLevel*.5+
Math.min(8,score/500);
player.vy+=.7;
player.y+=player.vy;
if(player.y>=310){
player.y=310;
player.vy=0;
player.onGround=true;
player.jumps=0;
}
if(
frame%
Math.max(
35,
85-Math.floor(score/120)
)===0
){
const h=
35+
Math.random()*55;
obstacles.push({
x:920,
y:365-h,
w:25+
Math.random()*30,
h
});
}
if(frame%50===0){
coinList.push({
x:920,
y:230+
Math.random()*100,
r:9
});
}
obstacles.forEach(
o=>o.x-=worldSpeed
);
coinList.forEach(c=>{
c.x-=worldSpeed;
if(magnetLevel>0){
const dx=
player.x-c.x;
const dy=
player.y+25-c.y;
const dist=
Math.hypot(dx,dy);
if(
dist<
100+
magnetLevel*30
){
c.x+=dx*.08;
c.y+=dy*.08;
}
}
});
obstacles=obstacles.filter(o=>{
if(o.x+o.w<0)
return false;
if(
player.x<o.x+o.w &&
player.x+player.w>o.x &&
player.y<o.y+o.h &&
player.y+player.h>o.y
){
if(player.shield>0){
player.shield--;
coinReward(2);
return false;
}
lives--;
if(lives<=0){
running=false;
best=Math.max(
best,
Math.floor(score)
);
save("run_best",best);
coinReward(
Math.floor(score/100)
);
document.getElementById(
"runNotice"
).textContent=
`GAME OVER โข ${Math.floor(score)} points`;
}
return false;
}
return true;
});
coinList=coinList.filter(c=>{
if(
Math.hypot(
player.x+18-c.x,
player.y+25-c.y
)<25
){
coins++;
/* REAL ARCADE COINS */
coinReward(1);
return false;
}
return c.x>-20;
});
document.getElementById(
"runScore"
).textContent=
Math.floor(score);
document.getElementById(
"runCoins"
).textContent=
coins;
document.getElementById(
"runLives"
).textContent=
lives;
document.getElementById(
"runBest"
).textContent=
best;
}
function draw(){
ctx.fillStyle="#070b20";
ctx.fillRect(
0,0,900,420
);
/* stars */
for(let i=0;i<60;i++){
const x=
(i*173-frame*.3)%900;
const y=
(i*71)%280;
ctx.fillStyle="#ffffff88";
ctx.fillRect(
(x+900)%900,
y,
2,
2
);
}
/* buildings */
ctx.fillStyle="#11182e";
for(
let x=0;
x<900;
x+=60
){
const h=
60+
(x*7%110);
ctx.fillRect(
x,
365-h,
45,
h
);
}
ctx.fillStyle="#111";
ctx.fillRect(
0,365,900,55
);
ctx.strokeStyle="#35e7ff55";
ctx.setLineDash(
[25,20]
);
ctx.beginPath();
ctx.moveTo(0,393);
ctx.lineTo(900,393);
ctx.stroke();
ctx.setLineDash([]);
/* player */
ctx.fillStyle="#35e7ff";
ctx.shadowBlur=20;
ctx.shadowColor="#35e7ff";
ctx.fillRect(
player.x,
player.y,
player.w,
player.h
);
ctx.shadowBlur=0;
obstacles.forEach(o=>{
ctx.fillStyle="#ff4fd8";
ctx.fillRect(
o.x,
o.y,
o.w,
o.h
);
});
coinList.forEach(c=>{
ctx.fillStyle="#ffd84d";
ctx.shadowBlur=15;
ctx.shadowColor="#ffd84d";
ctx.beginPath();
ctx.arc(
c.x,
c.y,
c.r,
0,
Math.PI*2
);
ctx.fill();
ctx.shadowBlur=0;
});
}
function loop(){
if(!running){
draw();
return;
}
update();
draw();
raf=
requestAnimationFrame(loop);
}
function moveLeft(){
if(running)
player.x=
Math.max(
20,
player.x-30
);
}
function moveRight(){
if(running)
player.x=
Math.min(
845,
player.x+30
);
}
const key=e=>{
if(
["ArrowUp"," ","w","W"]
.includes(e.key)
){
e.preventDefault();
jump();
}
if(
["ArrowLeft","a","A"]
.includes(e.key)
)
moveLeft();
if(
["ArrowRight","d","D"]
.includes(e.key)
)
moveRight();
};
document.addEventListener(
"keydown",
key
);
document.getElementById(
"runStart"
).onclick=reset;
document.getElementById(
"runJump"
).onclick=jump;
document.getElementById(
"runLeft"
).onclick=moveLeft;
document.getElementById(
"runRight"
).onclick=moveRight;
/* Upgrade buttons now use REAL arcade coins */
const upgrades=[
["runSpeedUp","run_speed","Speed Shoes",10],
["runJumpUp","run_jump","Double Jump",25],
["runShieldUp","run_shield","Shield",30],
["runMagnetUp","run_magnet","Coin Magnet",35]
];
upgrades.forEach(
([id,key,name,base])=>{
const button=
document.getElementById(id);
function refresh(){
const level=
load(key,0);
const cost=
base+
level*base;
button.textContent=
`${name} โข ${cost} ๐ช`;
}
button.onclick=()=>{
const level=
load(key,0);
const cost=
base+
level*base;
if(spendCoins(cost)){
save(
key,
level+1
);
if(key==="run_speed")
speedLevel++;
if(key==="run_jump")
jumpLevel++;
if(key==="run_shield")
shieldLevel++;
if(key==="run_magnet")
magnetLevel++;
refresh();
}
};
refresh();
}
);
reset();
return()=>{
cancelAnimationFrame(raf);
document.removeEventListener(
"keydown",
key
);
};
}
/* =========================================================
SNAKE
========================================================= */
function snakeEvolution(){
gameContent.innerHTML=`
<div class="game-stats">
<div class="game-stat">SCORE<strong id="snScore">0</strong></div>
<div class="game-stat">LEVEL<strong id="snLevel">1</strong></div>
<div class="game-stat">LENGTH<strong id="snLength">3</strong></div>
<div class="game-stat">BEST<strong id="snBest">0</strong></div>
</div>
<canvas id="snakeCanvas"
width="500"
height="500"></canvas>
<div class="touch-controls">
<button id="snLeft">โ</button>
<button id="snUp">โฒ</button>
<button id="snDown">โผ</button>
<button id="snRight">โถ</button>
</div>
<div class="controls">
<button class="btn primary"
id="snStart">
โถ Start / Restart
</button>
</div>
<div class="upgrades">
<div class="upgrade">
<h3>โก Speed Coil</h3>
<p>Increase snake speed.</p>
<button class="btn"
id="snSpeed"></button>
</div>
<div class="upgrade">
<h3>๐ Golden Food</h3>
<p>Increase golden food chance.</p>
<button class="btn"
id="snGold"></button>
</div>
<div class="upgrade">
<h3>โค๏ธ Extra Life</h3>
<p>Survive collisions.</p>
<button class="btn"
id="snLife"></button>
</div>
</div>
<div class="notice"
id="snNotice">
Eat the food!
</div>
`;
const canvas=
document.getElementById(
"snakeCanvas"
);
const ctx=
canvas.getContext("2d");
const grid=20;
const cell=25;
let speedLv=
load("snake_speed",0);
let goldLv=
load("snake_gold",0);
let lifeLv=
load("snake_life",0);
let best=
load("snake_best",0);
let snake;
let food;
let dir;
let nextDir;
let score;
let level;
let lives;
let running;
let timer;
function randomFood(){
let p;
do{
p={
x:Math.floor(
Math.random()*grid
),
y:Math.floor(
Math.random()*grid
),
gold:
Math.random()<
goldLv*.08
};
}while(
snake.some(
s=>
s.x===p.x &&
s.y===p.y
)
);
return p;
}
function start(){
snake=[
{x:10,y:10},
{x:9,y:10},
{x:8,y:10}
];
dir={x:1,y:0};
nextDir={x:1,y:0};
score=0;
level=1;
lives=lifeLv;
food=randomFood();
running=true;
schedule();
draw();
}
function schedule(){
clearTimeout(timer);
if(running){
timer=setTimeout(
tick,
Math.max(
65,
145-
speedLv*8-
level*4
)
);
}
}
function tick(){
dir=nextDir;
const head={
x:snake[0].x+dir.x,
y:snake[0].y+dir.y
};
const collision=
head.x<0 ||
head.x>=grid ||
head.y<0 ||
head.y>=grid ||
snake.some(
s=>
s.x===head.x &&
s.y===head.y
);
if(collision){
if(lives>0){
lives--;
snake=[
{x:10,y:10},
{x:9,y:10},
{x:8,y:10}
];
dir={x:1,y:0};
nextDir={x:1,y:0};
}else{
running=false;
best=Math.max(
best,
score
);
save(
"snake_best",
best
);
coinReward(
Math.floor(score/50)
);
document.getElementById(
"snNotice"
).textContent=
`GAME OVER โข ${score}`;
draw();
return;
}
}else{
snake.unshift(head);
if(
head.x===food.x &&
head.y===food.y
){
const points=
food.gold?50:10;
score+=points;
/* FOOD NOW EARNS ARCADE COINS */
if(food.gold){
coinReward(5);
}else{
coinReward(1);
}
food=randomFood();
level=
1+
Math.floor(
score/100
);
}else{
snake.pop();
}
}
updateStats();
draw();
schedule();
}
function updateStats(){
document.getElementById(
"snScore"
).textContent=score;
document.getElementById(
"snLevel"
).textContent=level;
document.getElementById(
"snLength"
).textContent=snake.length;
document.getElementById(
"snBest"
).textContent=best;
}
function draw(){
ctx.fillStyle="#050914";
ctx.fillRect(
0,0,500,500
);
for(
let x=0;
x<grid;
x++
){
for(
let y=0;
y<grid;
y++
){
ctx.fillStyle=
(x+y)%2
?" #0a1221".trim()
:"#0c1628";
ctx.fillRect(
x*cell,
y*cell,
cell,
cell
);
}
}
ctx.fillStyle=
food.gold
?" #ffd84d".trim()
:"#ff4f9a";
ctx.beginPath();
ctx.arc(
food.x*cell+cell/2,
food.y*cell+cell/2,
food.gold?9:7,
0,
Math.PI*2
);
ctx.fill();
snake.forEach(
(s,i)=>{
ctx.fillStyle=
i===0
?" #54f59a".trim()
:"#25b875";
ctx.fillRect(
s.x*cell+2,
s.y*cell+2,
cell-4,
cell-4
);
}
);
updateStats();
}
function setDir(x,y){
if(
dir.x===-x &&
dir.y===-y
)
return;
nextDir={x,y};
}
const key=e=>{
const map={
ArrowUp:[0,-1],
w:[0,-1],
W:[0,-1],
ArrowDown:[0,1],
s:[0,1],
S:[0,1],
ArrowLeft:[-1,0],
a:[-1,0],
A:[-1,0],
ArrowRight:[1,0],
d:[1,0],
D:[1,0]
};
if(map[e.key]){
e.preventDefault();
setDir(
...map[e.key]
);
}
};
document.addEventListener(
"keydown",
key
);
document.getElementById(
"snStart"
).onclick=start;
document.getElementById(
"snUp"
).onclick=()=>setDir(0,-1);
document.getElementById(
"snDown"
).onclick=()=>setDir(0,1);
document.getElementById(
"snLeft"
).onclick=()=>setDir(-1,0);
document.getElementById(
"snRight"
).onclick=()=>setDir(1,0);
/* REAL COIN UPGRADES */
function upgrade(
id,
key,
base
){
const button=
document.getElementById(id);
function refresh(){
const level=
load(key,0);
const cost=
base+
level*base;
button.textContent=
`Upgrade โข ${cost} ๐ช`;
}
button.onclick=()=>{
const level=
load(key,0);
const cost=
base+
level*base;
if(spendCoins(cost)){
save(
key,
level+1
);
refresh();
}
};
refresh();
}
upgrade(
"snSpeed",
"snake_speed",
10
);
upgrade(
"snGold",
"snake_gold",
15
);
upgrade(
"snLife",
"snake_life",
25
);
start();
return()=>{
clearTimeout(timer);
document.removeEventListener(
"keydown",
key
);
};
}
/* =========================================================
TARGET RUSH
========================================================= */
function targetRush(){
gameContent.innerHTML=`
<div class="game-stats">
<div class="game-stat">SCORE<strong id="tarScore">0</strong></div>
<div class="game-stat">TIME<strong id="tarTime">30</strong></div>
<div class="game-stat">COMBO<strong id="tarCombo">0x</strong></div>
<div class="game-stat">BEST<strong id="tarBest">0</strong></div>
</div>
<div class="target-area"
id="targetArea"></div>
<div class="controls">
<button class="btn primary"
id="tarStart">
โถ Start Round
</button>
</div>
<div class="upgrades">
<div class="upgrade">
<h3>โฑ๏ธ Time Warp</h3>
<p>Add more time.</p>
<button class="btn"
id="tarTimeUp"></button>
</div>
<div class="upgrade">
<h3>๐ฅ Combo Master</h3>
<p>Increase combo score.</p>
<button class="btn"
id="tarComboUp"></button>
</div>
<div class="upgrade">
<h3>๐ Slow Motion</h3>
<p>Targets remain longer.</p>
<button class="btn"
id="tarSlowUp"></button>
</div>
</div>
<div class="notice"
id="tarNotice">
Hit as many targets as possible!
</div>
`;
const area=
document.getElementById(
"targetArea"
);
let timeLv=
load("target_time",0);
let comboLv=
load("target_combo",0);
let slowLv=
load("target_slow",0);
let best=
load("target_best",0);
let score=0;
let combo=0;
let time=30;
let running=false;
let interval;
let targetTimer;
function spawn(){
area.innerHTML="";
const t=
document.createElement(
"div"
);
const roll=
Math.random();
t.className=
"target "+
(
roll<.12
?"bomb":
roll<.28
?"gold":
"normal"
);
t.textContent=
t.classList.contains("bomb")
?"ร":
t.classList.contains("gold")
?"โ
":
"+";
t.style.left=
(Math.random()*82+4)+"%";
t.style.top=
(Math.random()*78+5)+"%";
t.onclick=()=>{
if(!running)return;
if(
t.classList.contains(
"bomb"
)
){
score=
Math.max(
0,
score-25
);
combo=0;
}else{
combo++;
const points=
t.classList.contains(
"gold"
)
?30
:10;
score+=Math.floor(
points*
(1+combo*.08)*
(1+comboLv*.15)
);
/* TARGETS GIVE COINS */
if(
t.classList.contains(
"gold"
)
){
coinReward(3);
}else{
coinReward(1);
}
}
update();
spawn();
};
area.appendChild(t);
clearTimeout(
targetTimer
);
targetTimer=setTimeout(
()=>{
if(running)
spawn();
},
Math.max(
400,
1200-slowLv*100
)
);
}
function update(){
document.getElementById(
"tarScore"
).textContent=score;
document.getElementById(
"tarTime"
).textContent=
Math.max(
0,
time
).toFixed(1);
document.getElementById(
"tarCombo"
).textContent=
combo+"x";
document.getElementById(
"tarBest"
).textContent=
best;
}
function start(){
clearInterval(interval);
score=0;
combo=0;
time=
30+
timeLv*5;
running=true;
spawn();
update();
interval=setInterval(()=>{
time-=.1;
if(time<=0){
time=0;
running=false;
clearInterval(
interval
);
area.innerHTML="";
best=Math.max(
best,
score
);
save(
"target_best",
best
);
/* END OF ROUND REWARD */
const reward=
Math.floor(
score/25
);
coinReward(
reward
);
document.getElementById(
"tarNotice"
).textContent=
`ROUND COMPLETE! +${reward} ๐ช`;
}
update();
},100);
}
document.getElementById(
"tarStart"
).onclick=start;
function upgrade(
id,
key,
base
){
const button=
document.getElementById(id);
function refresh(){
const level=
load(key,0);
const cost=
base+
level*base;
button.textContent=
`Upgrade โข ${cost} ๐ช`;
}
button.onclick=()=>{
const level=
load(key,0);
const cost=
base+
level*base;
if(spendCoins(cost)){
save(
key,
level+1
);
refresh();
}
};
refresh();
}
upgrade(
"tarTimeUp",
"target_time",
20
);
upgrade(
"tarComboUp",
"target_combo",
25
);
upgrade(
"tarSlowUp",
"target_slow",
25
);
update();
return()=>{
clearInterval(interval);
clearTimeout(targetTimer);
};
}
/* =========================================================
MEMORY MASTER
========================================================= */
function memoryMaster(){
gameContent.innerHTML=`
<div class="game-stats">
<div class="game-stat">LEVEL<strong id="memLevel">1</strong></div>
<div class="game-stat">MOVES<strong id="memMoves">0</strong></div>
<div class="game-stat">TIME<strong id="memTime">0</strong></div>
<div class="game-stat">BEST<strong id="memBest">0</strong></div>
</div>
<div class="memory-grid"
id="memoryGrid"></div>
<div class="controls">
<button class="btn primary"
id="memNew">
๐ New Board
</button>
<button class="btn"
id="memHard">
๐ฅ Hard Mode
</button>
</div>
<div class="notice"
id="memNotice">
Find all matching pairs!
</div>
`;
const icons=[
"๐","๐พ","โญ","๐",
"๐ฅ","โก","๐ฎ","๐ธ",
"๐","๐ฒ","๐","๐"
];
let level=
load("memory_level",1);
let best=
load("memory_best",0);
let moves=0;
let seconds=0;
let first=null;
let second=null;
let lock=false;
let timer;
let hard=false;
function newBoard(){
clearInterval(timer);
moves=0;
seconds=0;
first=null;
second=null;
lock=false;
const pairs=
hard
?8
:Math.min(
6,
3+
Math.floor(level/2)
);
const chosen=
[...icons]
.sort(
()=>Math.random()-.5
)
.slice(0,pairs);
const cards=
[...chosen,...chosen]
.sort(
()=>Math.random()-.5
);
const grid=
document.getElementById(
"memoryGrid"
);
grid.innerHTML="";
cards.forEach(icon=>{
const card=
document.createElement(
"button"
);
card.className=
"memory-card";
card.dataset.icon=icon;
card.textContent=icon;
card.onclick=
()=>flip(card);
grid.appendChild(card);
});
timer=setInterval(()=>{
seconds++;
document.getElementById(
"memTime"
).textContent=
seconds;
},1000);
update();
}
function flip(card){
if(
lock||
card.classList.contains(
"flipped"
)||
card.classList.contains(
"matched"
)
)
return;
card.classList.add(
"flipped"
);
if(!first){
first=card;
return;
}
second=card;
moves++;
lock=true;
if(
first.dataset.icon===
second.dataset.icon
){
first.classList.add(
"matched"
);
second.classList.add(
"matched"
);
first=null;
second=null;
lock=false;
coinReward(2);
if(
document.querySelectorAll(
".memory-card.matched"
).length===
document.querySelectorAll(
".memory-card"
).length
){
clearInterval(timer);
const points=
Math.max(
10,
500-
seconds*5-
moves*10
);
best=Math.max(
best,
points
);
save(
"memory_best",
best
);
level++;
save(
"memory_level",
level
);
coinReward(
Math.floor(
points/25
)
);
document.getElementById(
"memNotice"
).textContent=
`๐ LEVEL COMPLETE!`;
}
}else{
setTimeout(()=>{
first.classList.remove(
"flipped"
);
second.classList.remove(
"flipped"
);
first=null;
second=null;
lock=false;
},650);
}
update();
}
function update(){
document.getElementById(
"memLevel"
).textContent=level;
document.getElementById(
"memMoves"
).textContent=moves;
document.getElementById(
"memTime"
).textContent=seconds;
document.getElementById(
"memBest"
).textContent=best;
}
document.getElementById(
"memNew"
).onclick=newBoard;
document.getElementById(
"memHard"
).onclick=()=>{
hard=!hard;
document.getElementById(
"memHard"
).textContent=
hard
?"โ๏ธ Normal Mode"
:"๐ฅ Hard Mode";
newBoard();
};
newBoard();
return()=>{
clearInterval(timer);
};
}
/* =========================================================
ASTEROID DODGE
========================================================= */
function asteroidDodge(){
gameContent.innerHTML=`
<div class="game-stats">
<div class="game-stat">SCORE<strong id="dodScore">0</strong></div>
<div class="game-stat">CREDITS<strong id="dodCredits">0</strong></div>
<div class="game-stat">SHIELD<strong id="dodShield">0</strong></div>
<div class="game-stat">BEST<strong id="dodBest">0</strong></div>
</div>
<canvas id="dodgeCanvas"
width="900"
height="450"></canvas>
<div class="touch-controls">
<button id="dodLeft">โ</button>
<button id="dodFire">๐ฅ</button>
<button id="dodRight">โถ</button>
</div>
<div class="controls">
<button class="btn primary"
id="dodStart">
โถ Launch Ship
</button>
</div>
<div class="upgrades">
<div class="upgrade">
<h3>๐ Engine</h3>
<p>Move faster.</p>
<button class="btn"
id="dodEngine"></button>
</div>
<div class="upgrade">
<h3>๐ก๏ธ Shield</h3>
<p>Absorb more hits.</p>
<button class="btn"
id="dodShield"></button>
</div>
<div class="upgrade">
<h3>๐ฅ Plasma Cannon</h3>
<p>Destroy asteroids.</p>
<button class="btn"
id="dodGun"></button>
</div>
</div>
<div class="notice"
id="dodNotice">
Avoid the asteroid field!
</div>
`;
const canvas=
document.getElementById(
"dodgeCanvas"
);
const ctx=
canvas.getContext("2d");
let engine=
load("dod_engine",0);
let shield=
load("dod_shield",0);
let gun=
load("dod_gun",0);
let best=
load("dod_best",0);
let score=0;
let credits=0;
let running=false;
let frame=0;
let raf;
let player;
let asteroids;
let bullets;
function start(){
score=0;
credits=0;
frame=0;
player={
x:450,
y:370,
hp:shield+1
};
asteroids=[];
bullets=[];
running=true;
loop();
}
function fire(){
if(!running)return;
bullets.push({
x:player.x,
y:player.y-20,
speed:10+gun
});
}
function update(){
frame++;
score++;
const spawnRate=
Math.max(
12,
38-
Math.floor(score/300)
);
if(
frame%spawnRate===0
){
asteroids.push({
x:Math.random()*870+15,
y:-40,
r:12+
Math.random()*22,
speed:
3+
Math.random()*3+
score/1000
});
}
asteroids.forEach(
a=>a.y+=a.speed
);
bullets.forEach(
b=>b.y-=b.speed
);
asteroids=
asteroids.filter(
a=>a.y<500
);
bullets=
bullets.filter(
b=>b.y>-20
);
for(
let i=asteroids.length-1;
i>=0;
i--
){
const a=
asteroids[i];
if(
Math.hypot(
a.x-player.x,
a.y-player.y
)<
a.r+18
){
player.hp--;
asteroids.splice(
i,
1
);
if(player.hp<=0){
running=false;
best=Math.max(
best,
score
);
save(
"dod_best",
best
);
coinReward(
Math.floor(
score/100
)
);
document.getElementById(
"dodNotice"
).textContent=
`SHIP DESTROYED โข ${score}`;
draw();
return;
}
}
}
for(
let i=asteroids.length-1;
i>=0;
i--
){
for(
let j=bullets.length-1;
j>=0;
j--
){
if(
Math.hypot(
asteroids[i].x-
bullets[j].x,
asteroids[i].y-
bullets[j].y
)<
asteroids[i].r+5
){
credits+=5;
/* Destroying asteroids earns coins */
coinReward(1);
asteroids.splice(
i,
1
);
bullets.splice(
j,
1
);
break;
}
}
}
document.getElementById(
"dodScore"
).textContent=score;
document.getElementById(
"dodCredits"
).textContent=credits;
document.getElementById(
"dodShield"
).textContent=player.hp;
document.getElementById(
"dodBest"
).textContent=best;
}
function draw(){
ctx.fillStyle="#03050c";
ctx.fillRect(
0,0,900,450
);
/* stars */
for(let i=0;i<80;i++){
const x=
(i*137)%900;
const y=
(i*73+frame*.4)%450;
ctx.fillStyle="#ffffff99";
ctx.fillRect(
x,
y,
2,
2
);
}
/* ship */
ctx.fillStyle="#35e7ff";
ctx.shadowBlur=25;
ctx.shadowColor="#35e7ff";
ctx.beginPath();
ctx.moveTo(
player.x,
player.y-25
);
ctx.lineTo(
player.x-18,
player.y+20
);
ctx.lineTo(
player.x,
player.y+12
);
ctx.lineTo(
player.x+18,
player.y+20
);
ctx.closePath();
ctx.fill();
ctx.shadowBlur=0;
/* asteroids */
asteroids.forEach(a=>{
ctx.fillStyle="#7b8399";
ctx.beginPath();
for(
let i=0;
i<8;
i++
){
const angle=
i*Math.PI/4;
const rr=
a.r*
(.75+
Math.sin(i*4)*.1);
const x=
a.x+
Math.cos(angle)*rr;
const y=
a.y+
Math.sin(angle)*rr;
if(i===0)
ctx.moveTo(x,y);
else
ctx.lineTo(x,y);
}
ctx.closePath();
ctx.fill();
});
ctx.fillStyle="#ffd84d";
bullets.forEach(
b=>{
ctx.fillRect(
b.x-2,
b.y-10,
4,
12
);
}
);
}
function loop(){
if(!running){
draw();
return;
}
update();
draw();
raf=
requestAnimationFrame(
loop
);
}
function left(){
if(running)
player.x=
Math.max(
20,
player.x-(8+engine)
);
}
function right(){
if(running)
player.x=
Math.min(
880,
player.x+(8+engine)
);
}
const key=e=>{
if(
["ArrowLeft","a","A"]
.includes(e.key)
)
left();
if(
["ArrowRight","d","D"]
.includes(e.key)
)
right();
if(e.key===" ")
fire();
};
document.addEventListener(
"keydown",
key
);
document.getElementById(
"dodStart"
).onclick=start;
document.getElementById(
"dodLeft"
).onclick=left;
document.getElementById(
"dodRight"
).onclick=right;
document.getElementById(
"dodFire"
).onclick=fire;
function upgrade(
id,
key,
base
){
const button=
document.getElementById(id);
function refresh(){
const level=
load(key,0);
const cost=
base+
level*base;
button.textContent=
`Upgrade โข ${cost} ๐ช`;
}
button.onclick=()=>{
const level=
load(key,0);
const cost=
base+
level*base;
if(spendCoins(cost)){
save(
key,
level+1
);
refresh();
}
};
refresh();
}
upgrade(
"dodEngine",
"dod_engine",
20
);
upgrade(
"dodShield",
"dod_shield",
30
);
upgrade(
"dodGun",
"dod_gun",
40
);
start();
return()=>{
cancelAnimationFrame(raf);
document.removeEventListener(
"keydown",
key
);
};
}
/* =========================================================
BRICK BREAKER
========================================================= */
function brickBreaker(){
gameContent.innerHTML=`
<div class="game-stats">
<div class="game-stat">SCORE<strong id="bbScore">0</strong></div>
<div class="game-stat">LEVEL<strong id="bbLevel">1</strong></div>
<div class="game-stat">LIVES<strong id="bbLives">3</strong></div>
<div class="game-stat">BEST<strong id="bbBest">0</strong></div>
</div>
<canvas id="brickCanvas"
width="850"
height="520"></canvas>
<div class="touch-controls">
<button id="bbLeft">โ</button>
<button id="bbLaunch">โ</button>
<button id="bbRight">โถ</button>
</div>
<div class="controls">
<button class="btn primary"
id="bbStart">
โถ Start / Restart
</button>
</div>
<div class="upgrades">
<div class="upgrade">
<h3>๐ Wide Paddle</h3>
<p>Increase paddle size.</p>
<button class="btn"
id="bbPaddle"></button>
</div>
<div class="upgrade">
<h3>๐ฅ Power Ball</h3>
<p>Break strong bricks faster.</p>
<button class="btn"
id="bbPower"></button>
</div>
<div class="upgrade">
<h3>โจ Multi Ball</h3>
<p>Chance to create another ball.</p>
<button class="btn"
id="bbMulti"></button>
</div>
<div class="upgrade">
<h3>โค๏ธ Extra Life</h3>
<p>Start with more lives.</p>
<button class="btn"
id="bbLife"></button>
</div>
</div>
<div class="notice"
id="bbNotice">
Break every brick!
</div>
`;
const canvas=
document.getElementById(
"brickCanvas"
);
const ctx=
canvas.getContext("2d");
let paddleLv=
load("bb_paddle",0);
let powerLv=
load("bb_power",0);
let multiLv=
load("bb_multi",0);
let lifeLv=
load("bb_life",0);
let best=
load("bb_best",0);
let score=0;
let level=1;
let lives=3;
let running=false;
let raf;
let paddle;
let balls;
let bricks;
function makeBricks(){
bricks=[];
const rows=
Math.min(
5+level,
9
);
const cols=10;
const gap=6;
const bw=74;
const bh=22;
for(
let r=0;
r<rows;
r++
){
for(
let c=0;
c<cols;
c++
){
bricks.push({
x:
20+
c*(bw+gap),
y:
55+
r*(bh+gap),
w:bw,
h:bh,
hp:
r%4===0
?2
:1
});
}
}
}
function reset(){
score=0;
level=1;
lives=
3+lifeLv;
paddle={
x:350,
y:480,
w:
130+
paddleLv*12,
h:15
};
balls=[
{
x:425,
y:450,
vx:4,
vy:-5
}
];
makeBricks();
running=true;
loop();
}
function launch(){
if(!running)return;
balls.forEach(
b=>{
b.vy=
-Math.abs(
b.vy||5
);
}
);
}
function update(){
balls.forEach(b=>{
b.x+=b.vx;
b.y+=b.vy;
if(
b.x<7 ||
b.x>843
)
b.vx*=-1;
if(b.y<7)
b.vy*=-1;
if(
b.y+8>=paddle.y &&
b.y-8<=
paddle.y+
paddle.h &&
b.x>=paddle.x &&
b.x<=
paddle.x+
paddle.w &&
b.vy>0
){
const hit=
(
b.x-
(
paddle.x+
paddle.w/2
)
)/
(
paddle.w/2
);
b.vx=hit*6;
b.vy=
-Math.abs(b.vy);
}
for(
let i=bricks.length-1;
i>=0;
i--
){
const br=
bricks[i];
if(
b.x+7>br.x &&
b.x-7<
br.x+br.w &&
b.y+7>br.y &&
b.y-7<
br.y+br.h
){
br.hp-=
powerLv>=2
?2
:1;
b.vy*=-1;
score+=
br.hp<=0
?10
:3;
if(br.hp<=0){
bricks.splice(
i,
1
);
/* Brick destroyed = arcade coin */
coinReward(1);
if(
multiLv>0 &&
Math.random()<
.05*multiLv
){
balls.push({
x:b.x,
y:b.y,
vx:-b.vx,
vy:b.vy
});
}
}
break;
}
}
});
if(bricks.length===0){
level++;
score+=
100*level;
coinReward(
10+level
);
makeBricks();
balls.forEach(
b=>{
b.vx*=1.06;
b.vy*=1.06;
}
);
}
balls=
balls.filter(
b=>b.y<540
);
if(balls.length===0){
lives--;
if(lives<=0){
running=false;
best=Math.max(
best,
score
);
save(
"bb_best",
best
);
coinReward(
Math.floor(
score/50
)
);
document.getElementById(
"bbNotice"
).textContent=
`GAME OVER โข ${score}`;
}else{
balls=[{
x:425,
y:450,
vx:4,
vy:-5
}];
}
}
updateStats();
}
function updateStats(){
document.getElementById(
"bbScore"
).textContent=score;
document.getElementById(
"bbLevel"
).textContent=level;
document.getElementById(
"bbLives"
).textContent=lives;
document.getElementById(
"bbBest"
).textContent=best;
}
function draw(){
ctx.fillStyle="#070c1b";
ctx.fillRect(
0,0,850,520
);
bricks.forEach(
br=>{
ctx.fillStyle=
br.hp===2
?" #9b6cff".trim()
:"#35e7ff";
ctx.fillRect(
br.x,
br.y,
br.w,
br.h
);
}
);
ctx.fillStyle="#ff4fd8";
ctx.fillRect(
paddle.x,
paddle.y,
paddle.w,
paddle.h
);
balls.forEach(
b=>{
ctx.fillStyle="#fff";
ctx.shadowBlur=18;
ctx.shadowColor="#ffd84d";
ctx.beginPath();
ctx.arc(
b.x,
b.y,
8,
0,
Math.PI*2
);
ctx.fill();
ctx.shadowBlur=0;
}
);
}
function loop(){
if(!running){
draw();
return;
}
update();
draw();
raf=
requestAnimationFrame(
loop
);
}
function left(){
paddle.x=
Math.max(
0,
paddle.x-35
);
}
function right(){
paddle.x=
Math.min(
850-paddle.w,
paddle.x+35
);
}
const key=e=>{
if(
["ArrowLeft","a","A"]
.includes(e.key)
)
left();
if(
["ArrowRight","d","D"]
.includes(e.key)
)
right();
if(e.key===" ")
launch();
};
document.addEventListener(
"keydown",
key
);
document.getElementById(
"bbStart"
).onclick=reset;
document.getElementById(
"bbLaunch"
).onclick=launch;
document.getElementById(
"bbLeft"
).onclick=left;
document.getElementById(
"bbRight"
).onclick=right;
canvas.addEventListener(
"mousemove",
e=>{
const rect=
canvas.getBoundingClientRect();
const x=
(
e.clientX-
rect.left
)/
rect.width*
850;
paddle.x=
Math.max(
0,
Math.min(
850-paddle.w,
x-paddle.w/2
)
);
}
);
/* REAL ARCADE COIN UPGRADES */
function upgrade(
id,
key,
base
){
const button=
document.getElementById(id);
function refresh(){
const level=
load(key,0);
const cost=
base+
level*base;
button.textContent=
`${cost} ๐ช Upgrade`;
}
button.onclick=()=>{
const level=
load(key,0);
const cost=
base+
level*base;
if(spendCoins(cost)){
save(
key,
level+1
);
refresh();
}
};
refresh();
}
upgrade(
"bbPaddle",
"bb_paddle",
20
);
upgrade(
"bbPower",
"bb_power",
30
);
upgrade(
"bbMulti",
"bb_multi",
40
);
upgrade(
"bbLife",
"bb_life",
35
);
reset();
return()=>{
cancelAnimationFrame(
raf
);
document.removeEventListener(
"keydown",
key
);
};
}
/* =========================================================
HIGHWAY RACER
========================================================= */
function highwayRacer(){
gameContent.innerHTML=`
<div class="game-stats">
<div class="game-stat">DISTANCE<strong id="raceDistance">0</strong></div>
<div class="game-stat">COINS<strong id="raceCoins">0</strong></div>
<div class="game-stat">SPEED<strong id="raceSpeed">0</strong></div>
<div class="game-stat">NITRO<strong id="raceNitro">100%</strong></div>
<div class="game-stat">BEST<strong id="raceBest">0</strong></div>
</div>
<canvas id="racerCanvas"
width="900"
height="450"></canvas>
<div class="touch-controls">
<button id="raceLeft">โ</button>
<button id="raceNitroBtn">๐ฅ</button>
<button id="raceRight">โถ</button>
</div>
<div class="controls">
<button class="btn primary"
id="raceStart">
๐ Start Race
</button>
</div>
<div class="upgrades">
<div class="upgrade">
<h3>๐ Engine</h3>
<p>Increase maximum speed.</p>
<button class="btn"
id="raceEngine"></button>
</div>
<div class="upgrade">
<h3>๐ Handling</h3>
<p>Turn faster.</p>
<button class="btn"
id="raceHandling"></button>
</div>
<div class="upgrade">
<h3>๐งฒ Coin Magnet</h3>
<p>Collect coins from farther away.</p>
<button class="btn"
id="raceMagnet"></button>
</div>
<div class="upgrade">
<h3>๐ฅ Nitro Tank</h3>
<p>Increase your nitro supply.</p>
<button class="btn"
id="raceNitro"></button>
</div>
<div class="upgrade">
<h3>๐ก๏ธ Armor</h3>
<p>Survive more crashes.</p>
<button class="btn"
id="raceArmor"></button>
</div>
</div>
<div class="notice"
id="raceNotice">
Use A/D or โ/โ โข Space for nitro
</div>
`;
const canvas=
document.getElementById(
"racerCanvas"
);
const ctx=
canvas.getContext("2d");
let engine=
load("race_engine",0);
let handling=
load("race_handling",0);
let magnet=
load("race_magnet",0);
let nitroLv=
load("race_nitro",0);
let armor=
load("race_armor",0);
let best=
load("race_best",0);
let distance=0;
let coins=0;
let speed=0;
let nitro=100;
let running=false;
let frame=0;
let raf;
let roadOffset=0;
let player;
let traffic;
let coinList;
function start(){
distance=0;
coins=0;
speed=
3+
engine*.5;
nitro=
100+
nitroLv*25;
frame=0;
roadOffset=0;
player={
x:450,
y:350,
w:45,
h:75,
hp:1+armor
};
traffic=[];
coinList=[];
running=true;
loop();
}
function spawnTraffic(){
if(
frame%
Math.max(
18,
55-
Math.floor(
distance/250
)
)===0
){
const lanes=[
280,
390,
500,
610
];
traffic.push({
x:
lanes[
Math.floor(
Math.random()*
lanes.length
)
],
y:-100,
w:44,
h:75,
speed:
2+
Math.random()*3
});
}
if(frame%35===0){
const lanes=[
280,
390,
500,
610
];
coinList.push({
x:
lanes[
Math.floor(
Math.random()*
lanes.length
)
],
y:-30,
r:8
});
}
}
function collide(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-a.h/2<
b.y+b.h/2 &&
a.y+a.h/2>
b.y-b.h/2
);
}
function update(){
frame++;
if(
speed<
12+engine
)
speed+=.01;
distance+=
speed*.04;
roadOffset=
(
roadOffset+
speed*3
)%80;
spawnTraffic();
traffic.forEach(
t=>
t.y+=
speed+t.speed
);
coinList.forEach(
c=>
c.y+=speed
);
traffic=
traffic.filter(
t=>t.y<520
);
coinList=
coinList.filter(
c=>c.y<500
);
for(
let i=traffic.length-1;
i>=0;
i--
){
if(
collide(
player,
traffic[i]
)
){
traffic.splice(
i,
1
);
player.hp--;
if(player.hp<=0){
running=false;
best=Math.max(
best,
Math.floor(
distance
)
);
save(
"race_best",
best
);
coinReward(
Math.floor(
distance/50
)
);
document.getElementById(
"raceNotice"
).textContent=
`CRASH! ${Math.floor(distance)}m`;
draw();
return;
}
}
}
for(
let i=coinList.length-1;
i>=0;
i--
){
const c=
coinList[i];
const dx=
player.x-c.x;
const dy=
player.y-c.y;
const d=
Math.hypot(
dx,
dy
);
if(
magnet>0 &&
d<
80+
magnet*30
){
c.x+=dx*.1;
c.y+=dy*.1;
}
if(d<35){
coins++;
/* REAL ARCADE COIN */
coinReward(1);
coinList.splice(
i,
1
);
}
}
document.getElementById(
"raceDistance"
).textContent=
Math.floor(
distance
)+"m";
document.getElementById(
"raceCoins"
).textContent=
coins;
document.getElementById(
"raceSpeed"
).textContent=
Math.floor(
speed*20
);
document.getElementById(
"raceNitro"
).textContent=
Math.floor(
nitro
)+"%";
document.getElementById(
"raceBest"
).textContent=
best;
}
function draw(){
ctx.clearRect(
0,0,900,450
);
/* grass */
ctx.fillStyle="#102719";
ctx.fillRect(
0,0,900,450
);
/* road */
ctx.fillStyle="#252932";
ctx.fillRect(
180,0,540,450
);
/* edges */
ctx.fillStyle="#ddd";
ctx.fillRect(
180,0,6,450
);
ctx.fillRect(
714,0,6,450
);
/* lane lines */
ctx.strokeStyle="#ffffff88";
ctx.lineWidth=5;
ctx.setLineDash(
[35,45]
);
ctx.lineDashOffset=
roadOffset;
for(
const x of [
312,
445,
578
]
){
ctx.beginPath();
ctx.moveTo(
x,
0
);
ctx.lineTo(
x,
450
);
ctx.stroke();
}
ctx.setLineDash([]);
traffic.forEach(
t=>
drawCar(
t.x,
t.y,
t.w,
t.h,
"#ff475e"
)
);
coinList.forEach(
c=>{
ctx.fillStyle=
"#ffd84d";
ctx.shadowBlur=18;
ctx.shadowColor=
"#ffd84d";
ctx.beginPath();
ctx.arc(
c.x,
c.y,
c.r,
0,
Math.PI*2
);
ctx.fill();
ctx.shadowBlur=0;
}
);
drawCar(
player.x,
player.y,
player.w,
player.h,
"#35e7ff"
);
if(nitro>0){
ctx.fillStyle="#54f59a";
ctx.fillRect(
player.x-7,
player.y+
player.h/2,
14,
25+
Math.random()*15
);
}
}
function drawCar(
x,
y,
w,
h,
color
){
ctx.fillStyle=color;
ctx.shadowBlur=18;
ctx.shadowColor=color;
ctx.fillRect(
x-w/2,
y-h/2,
w,
h
);
ctx.shadowBlur=0;
ctx.fillStyle="#10151e";
ctx.fillRect(
x-w/2+7,
y-h/2+10,
w-14,
22
);
ctx.fillStyle="#fff";
ctx.fillRect(
x-w/2+4,
y-h/2+5,
7,
10
);
ctx.fillRect(
x+w/2-11,
y-h/2+5,
7,
10
);
}
function loop(){
if(!running){
draw();
return;
}
update();
draw();
raf=
requestAnimationFrame(
loop
);
}
function left(){
if(running)
player.x=
Math.max(
215,
player.x-
(
10+
handling*3
)
);
}
function right(){
if(running)
player.x=
Math.min(
685,
player.x+
(
10+
handling*3
)
);
}
function useNitro(){
if(
running &&
nitro>0
){
speed=
Math.min(
20+engine,
speed+1
);
nitro-=3;
}
}
const key=e=>{
if(
["ArrowLeft","a","A"]
.includes(e.key)
)
left();
if(
["ArrowRight","d","D"]
.includes(e.key)
)
right();
if(e.key===" ")
useNitro();
};
document.addEventListener(
"keydown",
key
);
document.getElementById(
"raceStart"
).onclick=start;
document.getElementById(
"raceLeft"
).onclick=left;
document.getElementById(
"raceRight"
).onclick=right;
document.getElementById(
"raceNitroBtn"
).onclick=useNitro;
/* REAL COIN UPGRADES */
function upgrade(
id,
key,
base
){
const button=
document.getElementById(id);
function refresh(){
const level=
load(key,0);
const cost=
base+
level*base;
button.textContent=
`${cost} ๐ช Upgrade`;
}
button.onclick=()=>{
const level=
load(key,0);
const cost=
base+
level*base;
if(spendCoins(cost)){
save(
key,
level+1
);
refresh();
}
};
refresh();
}
upgrade(
"raceEngine",
"race_engine",
15
);
upgrade(
"raceHandling",
"race_handling",
20
);
upgrade(
"raceMagnet",
"race_magnet",
25
);
upgrade(
"raceNitro",
"race_nitro",
20
);
upgrade(
"raceArmor",
"race_armor",
35
);
start();
return()=>{
cancelAnimationFrame(
raf
);
document.removeEventListener(
"keydown",
key
);
};
}
</script>81,275 chars ยท codepastes.com