<!doctype html>
<html lang="tr">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title></title>
<style>
*{box-sizing:border-box}html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#090e20}
canvas{display:block;width:100%;height:100%;touch-action:none;outline:none}
</style>
<canvas tabindex="0" aria-label="收起灯光,避开红球"></canvas>
<script>
const c=document.querySelector('canvas'),g=c.getContext('2d');
let w,h,p,stars,foes,count,lives,mode,shield,last=0,target=null,elapsed=0;
const keys=new Set(),goal=12;
function size(){w=innerWidth;h=innerHeight;c.width=w*devicePixelRatio;c.height=h*devicePixelRatio;g.setTransform(devicePixelRatio,0,0,devicePixelRatio,0,0);reset()}
function point(){return{x:24+Math.random()*Math.max(1,w-48),y:85+Math.random()*Math.max(1,h-115)}}
function reset(){p={x:w/2,y:h/2};stars=Array.from({length:7},point);foes=Array.from({length:3},(_,i)=>({x:(i+1)*w/4,y:90,vx:65+i*15,vy:50+i*15}));count=0;lives=3;mode='play';shield=1.5;elapsed=0;target=null;keys.clear()}
function aim(e){const r=c.getBoundingClientRect();target={x:e.clientX-r.left,y:e.clientY-r.top}}
c.onpointermove=aim;
c.onpointerdown=e=>{c.focus();if(mode!=='play')reset();aim(e)};
c.onkeydown=e=>{if(['ArrowUp','ArrowDown','ArrowLeft','ArrowRight',' '].includes(e.key))e.preventDefault();if(mode!=='play'&&(e.key===' '||e.key==='Enter'))reset();keys.add(e.key.toLowerCase())};
c.onkeyup=e=>keys.delete(e.key.toLowerCase());
onblur=()=>keys.clear();onresize=size;
function ball(x,y,r,color){g.beginPath();g.arc(x,y,r,0,Math.PI*2);g.fillStyle=color;g.fill()}
function frame(t){const dt=Math.min((t-last)/1000||0,.035);last=t;elapsed+=dt;
if(mode==='play'){
shield=Math.max(0,shield-dt);
let dx=0,dy=0;if(keys.has('a')||keys.has('arrowleft'))dx--;if(keys.has('d')||keys.has('arrowright'))dx++;if(keys.has('w')||keys.has('arrowup'))dy--;if(keys.has('s')||keys.has('arrowdown'))dy++;
if(dx||dy){target=null;const n=Math.hypot(dx,dy);p.x+=dx/n*280*dt;p.y+=dy/n*280*dt}
else if(target){const x=target.x-p.x,y=target.y-p.y,n=Math.hypot(x,y),step=Math.min(n,320*dt);if(n){p.x+=x/n*step;p.y+=y/n*step}}
p.x=Math.max(16,Math.min(w-16,p.x));p.y=Math.max(72,Math.min(h-16,p.y));
for(let i=0;i<stars.length;i++)if(Math.hypot(p.x-stars[i].x,p.y-stars[i].y)<25){count++;stars[i]=point();if(count>=goal){mode='win';break}}
for(const f of foes){f.x+=f.vx*dt;f.y+=f.vy*dt;if(f.x<16||f.x>w-16){f.vx*=-1;f.x=Math.max(16,Math.min(w-16,f.x))}if(f.y<75||f.y>h-16){f.vy*=-1;f.y=Math.max(75,Math.min(h-16,f.y))}if(mode==='play'&&!shield&&Math.hypot(p.x-f.x,p.y-f.y)<29){lives--;shield=1.5;if(!lives)mode='lose'}}
}
g.fillStyle='#090e20';g.fillRect(0,0,w,h);
g.strokeStyle='#17213d';g.lineWidth=1;for(let x=0;x<w;x+=45){g.beginPath();g.moveTo(x,65);g.lineTo(x,h);g.stroke()}for(let y=65;y<h;y+=45){g.beginPath();g.moveTo(0,y);g.lineTo(w,y);g.stroke()}
g.fillStyle='#1d2944';g.fillRect(22,27,Math.max(1,w-130),8);g.fillStyle='#54e6c7';g.fillRect(22,27,Math.max(1,w-130)*Math.min(1,count/goal),8);
for(let i=0;i<3;i++)ball(w-76+i*23,31,6,i<lives?'#fb7185':'#28324c');
for(const s of stars){ball(s.x,s.y,11+Math.sin(elapsed*3+s.x)*2,'#173a49');ball(s.x,s.y,5,'#69f5d2')}
for(const f of foes){ball(f.x,f.y,18,'#421d35');ball(f.x,f.y,11,'#fb7185')}
if(!shield||Math.floor(elapsed*10)%2) {ball(p.x,p.y,21,'#352951');ball(p.x,p.y,13,'#b6a0ff');ball(p.x-4,p.y-4,4,'#f5f1ff')}
if(mode!=='play'){g.fillStyle='#090e20d9';g.fillRect(0,0,w,h);g.strokeStyle=mode==='win'?'#69f5d2':'#fb7185';g.lineWidth=5;g.beginPath();g.arc(w/2,h/2,45,0,Math.PI*2);g.stroke();g.fillStyle='#ffffff';g.beginPath();g.moveTo(w/2-9,h/2-17);g.lineTo(w/2+18,h/2);g.lineTo(w/2-9,h/2+17);g.closePath();g.fill()}
requestAnimationFrame(frame)}
size();requestAnimationFrame(frame);
</script>
</html>