🎮ArcadeLab

سباق السرعة

by PrismDolphin35
162 lines9.5 KB
▶ Play
from pathlib import Path

html = r'''<!doctype html>
<html lang="ar" dir="rtl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>سباق السرعة</title>
<style>
:root{--cyan:#35e6ff;--pink:#ff3f79;--bg:#07111d}
*{box-sizing:border-box}
body{margin:0;background:radial-gradient(circle at top,#18324a,#050a12 65%);color:white;font-family:system-ui,Arial,sans-serif;display:flex;justify-content:center;min-height:100vh}
.app{width:min(100%,760px);padding:14px}
h1{margin:4px 0 2px;text-align:center;font-size:clamp(24px,5vw,36px);letter-spacing:.5px}
.sub{text-align:center;color:#a9c7d8;font-size:13px;margin-bottom:12px}
.hud{display:flex;gap:8px;justify-content:space-between;flex-wrap:wrap;margin-bottom:8px}
.pill{background:#102336;border:1px solid #27516a;border-radius:12px;padding:8px 12px;flex:1;text-align:center;min-width:85px}
.pill b{display:block;color:var(--cyan);font-size:20px}
.gamebox{position:relative;border:2px solid #24506a;border-radius:18px;overflow:hidden;box-shadow:0 0 28px #00c9ff22}
canvas{display:block;width:100%;height:auto;background:#101b26;touch-action:none}
.overlay{position:absolute;inset:0;background:#03101bd9;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:22px}
.overlay h2{font-size:clamp(25px,6vw,40px);margin:0 0 8px;color:var(--cyan)}
.overlay p{max-width:400px;line-height:1.7;color:#d4e7f1;margin:0 0 18px}
button{border:0;border-radius:14px;padding:13px 20px;font-weight:800;font-size:16px;color:#06111a;background:linear-gradient(135deg,#5bf1ff,#39a8ff);box-shadow:0 5px 0 #17618c;cursor:pointer}
button:active{transform:translateY(2px);box-shadow:0 3px 0 #17618c}
.controls{display:grid;grid-template-columns:1fr 1fr 1.2fr;gap:10px;margin-top:12px}
.ctrl{min-height:62px;font-size:23px;touch-action:none}
.ctrl small{display:block;font-size:11px;opacity:.8}
#boost{background:linear-gradient(135deg,#ffde67,#ff8b3d);box-shadow:0 5px 0 #9b4a1c}
.help{text-align:center;color:#9db9c9;font-size:12px;line-height:1.7;margin:12px 0}
@media(min-width:600px){.controls{max-width:470px;margin:12px auto 0}}
</style>
</head>
<body>
<main class="app">
<h1>🏁 سباق السرعة</h1>
<div class="sub">تجاوز السيارات واجمع النقاط… ولا تصطدم!</div>
<div class="hud">
  <div class="pill">السرعة<b id="speed">0</b><span>كم/س</span></div>
  <div class="pill">النقاط<b id="score">0</b></div>
  <div class="pill">أفضل نتيجة<b id="best">0</b></div>
</div>
<div class="gamebox">
<canvas id="game" width="420" height="650" aria-label="لعبة سباق سيارات"></canvas>
<div class="overlay" id="overlay">
  <h2 id="overlayTitle">جاهز للانطلاق؟</h2>
  <p id="overlayText">قد سيارتك الرياضية على الطريق، تفادَ السيارات الأخرى واستخدم النيترو للاندفاع بسرعة!</p>
  <button id="start">ابدأ السباق 🚗</button>
</div>
</div>
<div class="controls">
  <button class="ctrl" id="left">⬅️<small>يسار</small></button>
  <button class="ctrl" id="right">➡️<small>يمين</small></button>
  <button class="ctrl" id="boost">⚡ نيترو<small>اضغط للاندفاع</small></button>
</div>
<div class="help">الكمبيوتر: استخدم ← → أو A و D للتحرك، واضغط Space للنيترو.<br>الهاتف: استخدم أزرار الاتجاهات والنيترو أسفل اللعبة.</div>
</main>
<script>
(()=>{
const canvas=document.getElementById('game'),ctx=canvas.getContext('2d');
const $=id=>document.getElementById(id);
let running=false, raf=0, last=0, score=0, speed=0, roadOffset=0, spawn=0, traffic=[], particles=[], keys={};
let best=Number(localStorage.getItem('speedRaceBest')||0);
$('best').textContent=best;
const car={x:210,y:520,w:42,h:76};
const road={left:52,right:368,width:316};
function rounded(x,y,w,h,r,fill,stroke){ctx.beginPath();ctx.roundRect(x,y,w,h,r);ctx.fillStyle=fill;ctx.fill();if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=2;ctx.stroke()}}
function drawCar(x,y,w,h,color,player=false){
  ctx.save();ctx.translate(x,y);
  // shadow
  ctx.fillStyle='#0008';ctx.beginPath();ctx.ellipse(3,h*.56,w*.7,h*.57,0,0,Math.PI*2);ctx.fill();
  rounded(-w/2-4,h*.18,8,h*.25,3,'#111820');rounded(w/2-4,h*.18,8,h*.25,3,'#111820');
  rounded(-w/2-4,h*.62,8,h*.24,3,'#111820');rounded(w/2-4,h*.62,8,h*.24,3,'#111820');
  rounded(-w/2,0,w,h,10,color,player?'#bafaff':'#ffd6df');
  // hood and windows
  rounded(-w*.34,h*.12,w*.68,h*.22,6,player?'#162f49':'#321b29','#ffffff55');
  rounded(-w*.32,h*.43,w*.64,h*.22,5,player?'#183c55':'#3b202a','#ffffff44');
  ctx.fillStyle=player?'#eaffff':'#fff4c9';ctx.fillRect(-w*.37,5,w*.19,5);ctx.fillRect(w*.18,5,w*.19,5);
  ctx.fillStyle='#ff365a';ctx.fillRect(-w*.38,h-9,w*.2,5);ctx.fillRect(w*.18,h-9,w*.2,5);
  if(player){ctx.fillStyle='#32eaff';ctx.shadowColor='#32eaff';ctx.shadowBlur=16;ctx.fillRect(-w*.24,h-2,w*.17,8);ctx.fillRect(w*.07,h-2,w*.17,8);ctx.shadowBlur=0}
  ctx.restore();
}
function drawRoad(dt){
  const g=ctx.createLinearGradient(0,0,420,0);g.addColorStop(0,'#102d29');g.addColorStop(.12,'#243a3a');g.addColorStop(.5,'#28313a');g.addColorStop(.88,'#243a3a');g.addColorStop(1,'#102d29');ctx.fillStyle=g;ctx.fillRect(0,0,420,650);
  // roadside dashes
  for(let y=-70+(roadOffset%90);y<700;y+=90){
    ctx.fillStyle='#f6f6e8';ctx.fillRect(43,y,7,48);ctx.fillRect(370,y,7,48);
    ctx.fillStyle='#e84156';ctx.fillRect(43,y+25,7,23);ctx.fillRect(370,y+25,7,23);
    ctx.fillStyle='#163b31';ctx.beginPath();ctx.arc(20,y+18,13,0,Math.PI*2);ctx.fill();ctx.beginPath();ctx.arc(400,y+58,16,0,Math.PI*2);ctx.fill();
  }
  ctx.fillStyle='#171e27';ctx.fillRect(52,0,316,650);
  ctx.fillStyle='#e8e8df';ctx.fillRect(52,0,5,650);ctx.fillRect(363,0,5,650);
  ctx.fillStyle='#f7f3d5';
  for(let y=-90+(roadOffset%110);y<700;y+=110){ctx.fillRect(155,y,5,58);ctx.fillRect(260,y,5,58)}
  // subtle road sheen
  const sheen=ctx.createLinearGradient(60,0,360,0);sheen.addColorStop(0,'#ffffff00');sheen.addColorStop(.5,'#ffffff0b');sheen.addColorStop(1,'#ffffff00');ctx.fillStyle=sheen;ctx.fillRect(58,0,304,650);
}
function draw(){
  ctx.clearRect(0,0,420,650);
  drawRoad(0);
  traffic.forEach(t=>drawCar(t.x,t.y,40,70,t.color));
  drawCar(car.x,car.y,car.w,car.h,'#08bde8',true);
  if(keys.boost&&running){
    for(let i=0;i<3;i++){particles.push({x:car.x+(Math.random()-.5)*20,y:car.y+car.h,v:2+Math.random()*5,a:1})}
  }
  particles=particles.filter(p=>p.a>0);
  particles.forEach(p=>{ctx.fillStyle=`rgba(62,225,255,${p.a})`;ctx.beginPath();ctx.arc(p.x,p.y,2+p.a*3,0,Math.PI*2);ctx.fill();p.y+=p.v;p.a-=.04});
}
function update(dt){
  if(!running)return;
  const boost=keys.boost?1.55:1;
  speed=Math.min(320,155+score*.025)*boost;
  roadOffset+=(speed/3)*dt/16.7;
  if(keys.left)car.x-=4.7*dt/16.7;
  if(keys.right)car.x+=4.7*dt/16.7;
  car.x=Math.max(78,Math.min(342,car.x));
  spawn+=dt;
  if(spawn>Math.max(430,930-score*.12)){
    spawn=0;
    const lanes=[105,207,312];const lane=lanes[Math.floor(Math.random()*lanes.length)];
    traffic.push({x:lane,y:-90,color:['#ef476f','#ffc857','#8b7bff','#63d471'][Math.floor(Math.random()*4)],v:2+Math.random()*2.4});
  }
  traffic.forEach(t=>t.y+=(2.4+t.v+speed/150)*(keys.boost?1.2:1)*dt/16.7);
  traffic=traffic.filter(t=>t.y<720);
  for(const t of traffic){
    if(Math.abs(t.x-car.x)<34&&t.y+62>car.y+8&&t.y<car.y+car.h-8){endGame();return}
  }
  score+=Math.max(1,Math.round(dt/35))*(keys.boost?2:1);
  $('score').textContent=score;
  $('speed').textContent=Math.round(speed);
}
function loop(now){const dt=Math.min(34,now-last||16);last=now;update(dt);draw();if(running)raf=requestAnimationFrame(loop)}
function endGame(){
  running=false;cancelAnimationFrame(raf);
  if(score>best){best=score;localStorage.setItem('speedRaceBest',best);$('best').textContent=best}
  $('overlayTitle').textContent='💥 انتهى السباق!';
  $('overlayText').innerHTML=`نتيجتك: <b style="color:#35e6ff">${score}</b> نقطة<br>أفضل نتيجة: <b style="color:#35e6ff">${best}</b><br>هل تستطيع تحطيم رقمك القياسي؟`;
  $('start').textContent='العب مرة أخرى 🔁';$('overlay').style.display='flex';
}
function start(){
  traffic=[];particles=[];score=0;speed=0;spawn=0;roadOffset=0;car.x=210;keys={};$('score').textContent='0';$('speed').textContent='0';
  $('overlay').style.display='none';running=true;last=performance.now();cancelAnimationFrame(raf);raf=requestAnimationFrame(loop);
}
$('start').addEventListener('click',start);
function hold(id,key){
  const el=$(id);
  const on=e=>{e.preventDefault();keys[key]=true;try{el.setPointerCapture(e.pointerId)}catch(_){}};
  const off=e=>{e.preventDefault();keys[key]=false};
  el.addEventListener('pointerdown',on);el.addEventListener('pointerup',off);el.addEventListener('pointercancel',off);el.addEventListener('lostpointercapture',()=>keys[key]=false);
}
hold('left','left');hold('right','right');hold('boost','boost');
window.addEventListener('keydown',e=>{if(['ArrowLeft','ArrowRight',' ','a','d','A','D'].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===' ')keys.boost=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===' ')keys.boost=false});
draw();
})();
</script>
</body>
</html>'''
path = Path("/mnt/data/sabaq_alsur3a.html")
path.write_text(html, encoding="utf-8")
print(f"تم إنشاء اللعبة: {path}")

Game Source: سباق السرعة

Creator: PrismDolphin35

Libraries: none

Complexity: moderate (162 lines, 9.5 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: game-prismdolphin35" to link back to the original. Then publish at arcadelab.ai/publish.