// === قفل الفريمات على 30 FPS === let fps = 30; let interval = 1000 / fps; let lastTime = 0; function loop30(timestamp){ if(timestamp - lastTime >= interval){ lastTime = timestamp; // هنا كل رسم اللعبة ctx.save();ctx.scale(DPR,DPR);ctx.clearRect(0,0,innerWidth,innerHeight); ctx.translate(innerWidth/2-p.x,innerHeight/2-p.y); zone-=0.35; if(zone<250)zone=250; zoneX+= (p.x-zoneX)*0.0003; zoneY+=(p.y-zoneY)*0.0003; document.getElementById('zn').innerText=(zone/18|0)+'%'; ctx.beginPath();ctx.arc(zoneX,zoneY,zone,0,Math.PI*2);ctx.strokeStyle='#ab47bc';ctx.lineWidth=10;ctx.setLineDash([18,12]);ctx.stroke();ctx.setLineDash([]); ctx.strokeStyle='#ffffff0a';for(let i=-2500;i<2500;i+=80){ctx.beginPath();ctx.moveTo(i,-2500);ctx.lineTo(i,2500);ctx.stroke();ctx.beginPath();ctx.moveTo(-2500,i);ctx.lineTo(2500,i);ctx.stroke()} structs.forEach(s=>{ctx.fillStyle=s.t=='wall'?'#8d6e63':s.t=='ramp'?'#a1887f':'#6d4c41';ctx.fillRect(s.x-s.w/2,s.y-s.h/2,s.w,s.h)}); enemies.forEach(e=>{if(!e.alive)return;let dx=p.x-e.x,dy=p.y-e.y,d=Math.hypot(dx,dy);e.x+=dx/d*2.8;e.y+=dy/d*2.8;ctx.fillStyle='#7c4dff';ctx.beginPath();ctx.arc(e.x,e.y,13,0,Math.PI*2);ctx.fill();if(d<32&&Date.now()-e.cd>900){e.cd=Date.now();hp-=12;document.getElementById('hp').innerText=hp|0;if(hp<=0){alert('GG!');location.reload()}}}); for(let i=bullets.length-1;i>=0;i--){let b=bullets[i];b.x+=b.dx*b.spd;b.y+=b.dy*b.spd;b.life--;ctx.fillStyle='#ffeb3b';ctx.beginPath();ctx.arc(b.x,b.y,4.5,0,Math.PI*2);ctx.fill();enemies.forEach(e=>{if(e.alive&&Math.hypot(b.x-e.x,b.y-e.y)<16){e.hp-=b.dmg;bullets.splice(i,1);if(e.hp<=0){e.alive=false;kills++;mt+=40;document.getElementById('mt').innerText=mt;document.getElementById('kl').innerText=kills}}});if(b.life<=0)bullets.splice(i,1);} ctx.fillStyle='#ff3b3b';ctx.beginPath();ctx.arc(p.x,p.y,15,0,Math.PI*2);ctx.fill(); if(Math.hypot(p.x-zoneX,p.y-zoneY)>zone){hp-=1.2;document.getElementById('hp').innerText=hp|0} ctx.restore(); } requestAnimationFrame(loop30); } requestAnimationFrame(loop30);