star_breaker_stg_stage5_power_barrage.html

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>STAR BREAKER - 5 STAGE STG</title>
<style>
:root{--cyan:#55efff;--pink:#ff4fd8;--yellow:#ffe66d;--bg:#02040e}
*{box-sizing:border-box}
html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#02040e;color:#fff;font-family:system-ui,-apple-system,"Yu Gothic UI",sans-serif}
body{display:grid;place-items:center;background:radial-gradient(circle at 50% 20%,#17265e,#050817 50%,#010208)}
#wrap{position:relative;width:min(100vw,900px);height:min(100vh,960px);aspect-ratio:3/4;overflow:hidden;border:1px solid #55efff55;box-shadow:0 0 36px #55efff22;background:#02040e}
canvas{display:block;width:100%;height:100%;touch-action:none;cursor:crosshair}
#hud{position:absolute;inset:0;pointer-events:none;font-weight:900;text-shadow:0 0 8px #55efff}
.top{position:absolute;top:12px;left:16px;right:16px;display:flex;justify-content:space-between;gap:12px;font-size:clamp(12px,2vw,19px)}
#stageLabel{position:absolute;top:45px;left:0;right:0;text-align:center;color:#bff8ff;letter-spacing:.22em}
#bossWrap{display:none;position:absolute;top:73px;left:9%;width:82%}
#bossName{text-align:center;font-size:13px;margin-bottom:5px;color:#ffd4f5}
.bar{height:13px;border:1px solid #ffffffaa;background:#ffffff12}
#bossHp{height:100%;width:100%;background:linear-gradient(90deg,#ff4fd8,#ff9a3d)}
.overlay{position:absolute;inset:0;display:grid;place-items:center;background:linear-gradient(#02040e33,#02040ecc);z-index:5}
.panel{width:min(88%,650px);padding:clamp(22px,5vw,44px);text-align:center;background:#081027e8;border:1px solid #55efff88;box-shadow:0 0 28px #55efff33;backdrop-filter:blur(7px)}
h1{margin:0 0 10px;font-size:clamp(38px,8vw,76px);line-height:.9;color:#fff;text-shadow:0 0 9px #fff,0 0 22px #55efff,4px 4px 0 #ff4fd8}
.sub{color:#8deeff;letter-spacing:.25em;margin-bottom:22px;font-weight:800}
#message{line-height:1.8;color:#ddebff}
button{margin:20px 7px 0;padding:14px 28px;border:0;border-radius:999px;color:#fff;font-weight:900;font-size:17px;cursor:pointer;background:linear-gradient(90deg,#55efff,#7277ff,#ff4fd8);box-shadow:0 0 18px #55efff66}
button.secondary{background:#252c46;box-shadow:none;border:1px solid #ffffff44}
button:hover{filter:brightness(1.15);transform:scale(1.03)}
.small{margin-top:18px;padding-top:14px;border-top:1px solid #ffffff22;color:#b7c9dd;font-size:13px;line-height:1.7}
#mobile{position:absolute;left:0;right:0;bottom:12px;display:none;justify-content:space-between;padding:0 14px;pointer-events:none;z-index:4}
.group{display:flex;gap:8px;pointer-events:auto}.touch{width:58px;height:58px;margin:0;padding:0;border-radius:50%;opacity:.62;font-size:20px}
@media(pointer:coarse){#mobile{display:flex}}
</style>
</head>
<body>
<div id="wrap">
<canvas id="game" width="720" height="960"></canvas>

<div id="hud">
  <div class="top">
    <div>SCORE <span id="score">0000000</span></div>
    <div>HI <span id="high">0000000</span></div>
    <div>POWER <span id="power">1</span></div>
  </div>
  <div id="stageLabel">STAGE 1 / 5</div>
  <div id="bossWrap">
    <div id="bossName">BOSS</div>
    <div class="bar"><div id="bossHp"></div></div>
  </div>
</div>

<div id="overlay" class="overlay">
  <div class="panel">
    <h1 id="title">STAR<br>BREAKER</h1>
    <div class="sub" id="subtitle">5 STAGE MISSION</div>
    <div id="message">全5ステージを突破し、最終要塞を破壊せよ。<br>敵弾に一発でも当たると爆発してゲームオーバー。<br>POWERアイテムでショットを最大5段階まで強化。</div>
    <div id="buttons">
      <button id="startBtn">GAME START</button>
    </div>
    <div class="small">PC:WASD / 矢印キー / マウスドラッグで移動 | P:一時停止<br>スマホ:画面ドラッグ、または下の移動ボタン</div>
  </div>
</div>

<div id="mobile">
  <div class="group"><button class="touch" data-key="left">◀</button><button class="touch" data-key="right">▶</button></div>
  <div class="group"><button class="touch" data-key="up">▲</button><button class="touch" data-key="down">▼</button></div>
</div>
</div>

<script>
(()=>{
"use strict";
const canvas=document.getElementById("game"),ctx=canvas.getContext("2d");
const W=720,H=960;
const scoreEl=document.getElementById("score"),highEl=document.getElementById("high"),powerEl=document.getElementById("power");
const stageLabel=document.getElementById("stageLabel"),bossWrap=document.getElementById("bossWrap"),bossName=document.getElementById("bossName"),bossHp=document.getElementById("bossHp");
const overlay=document.getElementById("overlay"),title=document.getElementById("title"),subtitle=document.getElementById("subtitle"),message=document.getElementById("message"),buttons=document.getElementById("buttons");

let running=false,paused=false,dead=false,last=0,time=0,score=0,high=Number(localStorage.getItem("starBreaker5High")||0);
let stage=1,stageTime=0,waveTimer=0,wavesSpawned=0,bossActive=false,transition=false,shake=0,flash=0;
let pointer=false;
const keys={},bullets=[],enemyBullets=[],enemies=[],particles=[],powerups=[],stars=[];

const stageData=[
 {name:"ORBITAL FRONT",duration:23,boss:"IRON TALON",hp:260,bg:["#07112c","#02040e"]},
 {name:"CRIMSON NEBULA",duration:25,boss:"SCARLET MANTA",hp:380,bg:["#2b071c","#07030b"]},
 {name:"ASTEROID BELT",duration:27,boss:"GRAVITY GOLEM",hp:520,bg:["#241b10","#050403"]},
 {name:"VOID TEMPLE",duration:29,boss:"ABYSS SERAPH",hp:700,bg:["#16072a","#030109"]},
 {name:"FINAL FORTRESS",duration:32,boss:"OMEGA EMPRESS",hp:980,bg:["#051b26","#010408"]}
];

const player={x:W/2,y:H-120,r:11,speed:410,cool:0,rate:.12,power:1,maxPower:5,inv:0,tilt:0};
for(let i=0;i<150;i++)stars.push({x:Math.random()*W,y:Math.random()*H,z:Math.random()*2.5+.5,a:Math.random()*.8+.2});

function clearAll(){bullets.length=enemyBullets.length=enemies.length=particles.length=powerups.length=0}
function updateHUD(){
 scoreEl.textContent=String(Math.floor(score)).padStart(7,"0");
 highEl.textContent=String(Math.floor(high)).padStart(7,"0");
 powerEl.textContent=player.power>=player.maxPower?"MAX":player.power;
 stageLabel.textContent=`STAGE ${stage} / 5 ${stageData[stage-1].name}`;
}
function reset(){
 clearAll();stage=1;stageTime=0;waveTimer=0;wavesSpawned=0;bossActive=false;transition=false;dead=false;paused=false;
 score=0;time=0;shake=0;flash=0;player.x=W/2;player.y=H-120;player.cool=0;player.power=1;player.inv=1;
 bossWrap.style.display="none";updateHUD();
}
function begin(){
 reset();running=true;overlay.style.display="none";last=performance.now();requestAnimationFrame(loop);
}
function addScore(n){
 score+=n;if(score>high){high=score;localStorage.setItem("starBreaker5High",String(Math.floor(high)))}updateHUD();
}
function burst(x,y,color,count=25,speed=260){
 for(let i=0;i<count;i++){const a=Math.random()*Math.PI*2,s=Math.random()*speed+40;
 particles.push({x,y,vx:Math.cos(a)*s,vy:Math.sin(a)*s,life:Math.random()*.7+.3,max:1,size:Math.random()*6+2,color});
 }}
function shoot(){
 let shots=[];
 if(player.power===1)shots=[{a:0,x:0,d:1}];
 if(player.power===2)shots=[{a:-.10,x:-7,d:1},{a:.10,x:7,d:1}];
 if(player.power===3)shots=[{a:-.18,x:-10,d:1},{a:0,x:0,d:2},{a:.18,x:10,d:1}];
 if(player.power===4)shots=[{a:-.25,x:-15,d:2},{a:-.08,x:-5,d:2},{a:.08,x:5,d:2},{a:.25,x:15,d:2}];
 if(player.power>=5)shots=[
   {a:-.31,x:-18,d:2},{a:-.16,x:-10,d:2},{a:0,x:0,d:3},
   {a:.16,x:10,d:2},{a:.31,x:18,d:2}
 ];
 shots.forEach(s=>bullets.push({
   x:player.x+s.x,y:player.y-20,
   vx:Math.sin(s.a)*230,vy:-820,
   r:s.d>=3?7:5,dmg:s.d,power:player.power
 }));
 player.rate=Math.max(.065,.13-player.power*.013);
}
function spawnEnemy(type,x,y){
 const s=stage;
 if(type==="scout")enemies.push({type,x,y,r:19,hp:1+s,maxHp:1+s,vx:(Math.random()-.5)*130,vy:105+s*11,age:0,shot:1.2+Math.random()});
 if(type==="zig")enemies.push({type,x,y,r:22,hp:3+s,maxHp:3+s,vx:0,vy:80+s*7,age:Math.random()*5,shot:.9+Math.random()});
 if(type==="tank")enemies.push({type,x,y,r:32,hp:11+s*4,maxHp:11+s*4,vx:0,vy:42+s*3,age:0,shot:.7});
}
function spawnWave(){
 wavesSpawned++;
 const pattern=(wavesSpawned+stage)%4;
 if(pattern===0){for(let i=0;i<7;i++)spawnEnemy("scout",75+i*95,-40-i*34)}
 if(pattern===1){for(let i=0;i<6;i++)spawnEnemy("zig",90+i*108,-45-i*70)}
 if(pattern===2){spawnEnemy("tank",W/2,-70);for(let i=0;i<4;i++)spawnEnemy("scout",120+i*160,-160-i*40)}
 if(pattern===3){for(let i=0;i<3;i++){spawnEnemy("zig",170+i*190,-60-i*80);spawnEnemy("scout",90+i*250,-190-i*50)}}
}
function spawnBoss(){
 bossActive=true;enemyBullets.length=0;
 const d=stageData[stage-1];
 enemies.push({type:"boss",x:W/2,y:-130,r:82,hp:d.hp,maxHp:d.hp,age:0,shot:.6,stage,vy:48});
 bossName.textContent=d.boss;bossHp.style.width="100%";bossWrap.style.display="block";
}
function addEnemyBullet(x,y,a,speed,r=7,color="#ff8ae7"){
 enemyBullets.push({x,y,vx:Math.cos(a)*speed,vy:Math.sin(a)*speed,r,color});
}
function enemyShoot(e){
 const aim=Math.atan2(player.y-e.y,player.x-e.x);
 const base=145+stage*18;

 if(e.type==="scout"){
   if(stage<=2){
     for(let i=-1;i<=1;i++)addEnemyBullet(e.x,e.y,aim+i*.12,base,6,"#ff8ae7");
   }else{
     for(let i=-2;i<=2;i++)addEnemyBullet(e.x,e.y,aim+i*.13,base+12,6,"#ff8ae7");
   }
 }

 if(e.type==="zig"){
   const count=5+stage;
   for(let i=0;i<count;i++){
     const a=(i/(count-1)-.5)*1.15+Math.PI/2;
     addEnemyBullet(e.x,e.y,a,145+stage*12,6,"#9d8cff");
   }
   addEnemyBullet(e.x,e.y,aim,210+stage*8,5,"#ffffff");
 }

 if(e.type==="tank"){
   const n=10+stage*2;
   for(let i=0;i<n;i++){
     const a=i*Math.PI*2/n+e.age*.32;
     addEnemyBullet(e.x,e.y,a,125+stage*10,7,"#ffb25f");
   }
   for(let i=-2;i<=2;i++)addEnemyBullet(e.x,e.y,aim+i*.15,190+stage*10,6,"#fff0a8");
 }

 if(e.type==="boss"){
   const ratio=e.hp/e.maxHp;

   if(e.stage===1){
     for(let ring=0;ring<2;ring++){
       for(let i=-5;i<=5;i++){
         const a=aim+i*.12+(ring?0.055:0);
         addEnemyBullet(e.x,e.y+35,a,195+ring*45,7,ring?"#ffd1f4":"#ff78d8");
       }
     }
   }

   if(e.stage===2){
     const n=22;
     for(let i=0;i<n;i++){
       const a=i*Math.PI*2/n+e.age*.62;
       addEnemyBullet(e.x,e.y,a,155+(i%2)*42,7,i%2?"#ff7ac8":"#a884ff");
     }
     for(let i=-2;i<=2;i++)addEnemyBullet(e.x,e.y+25,aim+i*.13,235,6,"#ffffff");
   }

   if(e.stage===3){
     for(let ring=0;ring<3;ring++){
       const n=12+ring*4;
       for(let i=0;i<n;i++){
         const a=i*Math.PI*2/n+e.age*(ring%2?-.42:.42);
         addEnemyBullet(e.x,e.y,a,115+ring*42,8-ring,"#ffb35f");
       }
     }
   }

   if(e.stage===4){
     for(let side=-1;side<=1;side+=2){
       for(let i=0;i<9;i++){
         const a=aim+side*(.08+i*.085)+Math.sin(e.age*1.8)*.18;
         addEnemyBullet(e.x+side*45,e.y+20,a,205+i*6,6,"#b477ff");
       }
     }
     if(ratio<.5){
       for(let i=0;i<18;i++){
         const a=i*Math.PI/9-e.age*.55;
         addEnemyBullet(e.x,e.y,a,175,7,"#ff70dd");
       }
     }
   }

   if(e.stage===5){
     const n=ratio>.6?28:38;
     for(let i=0;i<n;i++){
       const a=i*Math.PI*2/n+e.age*.78;
       addEnemyBullet(e.x,e.y,a,150+(i%4)*28,7,i%2?"#ff4fd8":"#65eaff");
     }
     for(let i=-5;i<=5;i++)addEnemyBullet(e.x,e.y+42,aim+i*.095,250,6,"#fff2a8");
     if(ratio<.45){
       for(let i=0;i<20;i++){
         const a=i*Math.PI/10-e.age*1.05;
         addEnemyBullet(e.x,e.y,a,225,5,"#ffffff");
       }
     }
   }
 }
}
function collide(a,b){const dx=a.x-b.x,dy=a.y-b.y;return dx*dx+dy*dy<(a.r+b.r)*(a.r+b.r)}
function gameOver(){
 if(dead)return;dead=true;running=false;shake=34;flash=.75;
 burst(player.x,player.y,"#ff4fd8",120,430);burst(player.x,player.y,"#ffe66d",80,360);
 draw();
 setTimeout(()=>{
  title.innerHTML="GAME<br>OVER";subtitle.textContent="SHIP DESTROYED";
  message.innerHTML=`敵弾に命中し、機体が爆発した。<br>SCORE:<b>${Math.floor(score).toLocaleString()}</b> STAGE:<b>${stage}</b>`;
  buttons.innerHTML='<button id="retryBtn">リトライ</button><button id="quitBtn" class="secondary">やめる</button>';
  overlay.style.display="grid";
  document.getElementById("retryBtn").addEventListener("click",begin);
  document.getElementById("quitBtn").addEventListener("click",quitGame);
 },650);
}
function quitGame(){
 clearAll();dead=false;bossWrap.style.display="none";
 title.innerHTML="STAR<br>BREAKER";subtitle.textContent="MISSION ABORTED";
 message.innerHTML="ゲームを終了しました。<br>もう一度遊ぶときはスタートを押してください。";
 buttons.innerHTML='<button id="againBtn">GAME START</button>';
 document.getElementById("againBtn").addEventListener("click",begin);
 draw();
}
function stageClear(){
 transition=true;bossActive=false;bossWrap.style.display="none";enemyBullets.length=0;clearAll();
 addScore(2500*stage);
 if(stage===5){running=false;title.innerHTML="ALL<br>CLEAR";subtitle.textContent="OMEGA FORTRESS DESTROYED";
  message.innerHTML=`全5ステージ制覇!<br>FINAL SCORE:<b>${Math.floor(score).toLocaleString()}</b>`;
  buttons.innerHTML='<button id="retryAll">もう一度遊ぶ</button><button id="quitAll" class="secondary">やめる</button>';
  overlay.style.display="grid";
  document.getElementById("retryAll").addEventListener("click",begin);
  document.getElementById("quitAll").addEventListener("click",quitGame);
  return;
 }
 running=false;title.innerHTML=`STAGE ${stage}<br>CLEAR`;subtitle.textContent=stageData[stage-1].boss+" DESTROYED";
 message.innerHTML=`次は STAGE ${stage+1}「${stageData[stage].name}」`;
 buttons.innerHTML='<button id="nextStage">NEXT STAGE</button>';
 overlay.style.display="grid";
 document.getElementById("nextStage").addEventListener("click",()=>{
   stage++;stageTime=0;waveTimer=0;wavesSpawned=0;transition=false;player.x=W/2;player.y=H-120;player.inv=1.5;
   updateHUD();overlay.style.display="none";running=true;last=performance.now();requestAnimationFrame(loop);
 });
}
function update(dt){
 time+=dt;stageTime+=dt;if(player.inv>0)player.inv-=dt;if(shake>0)shake=Math.max(0,shake-dt*55);if(flash>0)flash=Math.max(0,flash-dt*1.7);
 stars.forEach(s=>{s.y+=(55+s.z*65+stage*8)*dt;if(s.y>H){s.y=-5;s.x=Math.random()*W}});
 let dx=0,dy=0;if(keys.ArrowLeft||keys.a||keys.left)dx--;if(keys.ArrowRight||keys.d||keys.right)dx++;if(keys.ArrowUp||keys.w||keys.up)dy--;if(keys.ArrowDown||keys.s||keys.down)dy++;
 const l=Math.hypot(dx,dy)||1;dx/=l;dy/=l;player.x+=dx*player.speed*dt;player.y+=dy*player.speed*dt;player.x=Math.max(25,Math.min(W-25,player.x));player.y=Math.max(95,Math.min(H-35,player.y));player.tilt+=(dx*.45-player.tilt)*Math.min(1,dt*10);
 player.cool-=dt;if(player.cool<=0){shoot();player.cool=player.rate}
 if(!bossActive){
   waveTimer-=dt;if(waveTimer<=0){spawnWave();waveTimer=Math.max(2.5,4.6-stage*.28)}
   if(stageTime>=stageData[stage-1].duration)spawnBoss();
 }
 for(let i=bullets.length-1;i>=0;i--){const b=bullets[i];b.x+=b.vx*dt;b.y+=b.vy*dt;if(b.y<-30||b.x<-30||b.x>W+30)bullets.splice(i,1)}
 for(let i=enemyBullets.length-1;i>=0;i--){const b=enemyBullets[i];b.x+=b.vx*dt;b.y+=b.vy*dt;if(b.y>H+50||b.y<-60||b.x<-60||b.x>W+60){enemyBullets.splice(i,1);continue}if(player.inv<=0&&collide(b,player)){enemyBullets.splice(i,1);gameOver();return}}
 for(let i=enemies.length-1;i>=0;i--){const e=enemies[i];e.age+=dt;
   if(e.type==="scout"){e.x+=e.vx*dt;e.y+=e.vy*dt;if(e.x<30||e.x>W-30)e.vx*=-1}
   if(e.type==="zig"){e.y+=e.vy*dt;e.x+=Math.sin(e.age*2.5)*125*dt}
   if(e.type==="tank"){e.y+=e.vy*dt;e.x=W/2+Math.sin(e.age*.85)*220}
   if(e.type==="boss"){if(e.y<165)e.y+=e.vy*dt;else e.x=W/2+Math.sin(e.age*(.55+e.stage*.06))*245;bossHp.style.width=Math.max(0,e.hp/e.maxHp*100)+"%"}
   e.shot-=dt;if(e.shot<=0&&e.y>0){enemyShoot(e);e.shot=e.type==="boss"?Math.max(.22,.62-stage*.065):e.type==="tank"?1.08:e.type==="zig"?.92:1.12}
   for(let j=bullets.length-1;j>=0;j--){const b=bullets[j];if(collide(b,e)){e.hp-=b.dmg;bullets.splice(j,1);burst(b.x,b.y,"#ffe66d",4,80);
     if(e.hp<=0){const boss=e.type==="boss";burst(e.x,e.y,boss?"#ff4fd8":"#55efff",boss?130:28,boss?430:230);shake=boss?30:7;
       addScore(boss?5000*stage:e.type==="tank"?550:e.type==="zig"?220:100);
       if(!boss){
         const dropRate=e.type==="tank"?.60:e.type==="zig"?.32:.20;
         if(Math.random()<dropRate)powerups.push({x:e.x,y:e.y,r:15,vy:82,spin:0});
       }
       enemies.splice(i,1);if(boss){enemyBullets.length=0;setTimeout(stageClear,550)}break;
     }}}
   if(i<enemies.length&&e.y>H+100)enemies.splice(i,1);
   else if(i<enemies.length&&player.inv<=0&&collide(e,player)){gameOver();return}
 }
 for(let i=powerups.length-1;i>=0;i--){const p=powerups[i];p.y+=p.vy*dt;p.spin+=dt*4;if(collide(p,player)){player.power=Math.min(player.maxPower,player.power+1);addScore(player.power>=player.maxPower?800:400);burst(p.x,p.y,"#ffe66d",20,190);powerups.splice(i,1);updateHUD()}else if(p.y>H+30)powerups.splice(i,1)}
 for(let i=particles.length-1;i>=0;i--){const p=particles[i];p.x+=p.vx*dt;p.y+=p.vy*dt;p.vx*=.984;p.vy*=.984;p.life-=dt;if(p.life<=0)particles.splice(i,1)}
}
function drawShip(){
 ctx.save();ctx.translate(player.x,player.y);ctx.rotate(player.tilt);if(player.inv>0&&Math.floor(player.inv*13)%2===0)ctx.globalAlpha=.3;
 ctx.shadowBlur=22;ctx.shadowColor="#55efff";ctx.fillStyle="#e9fdff";ctx.beginPath();ctx.moveTo(0,-27);ctx.lineTo(18,19);ctx.lineTo(0,10);ctx.lineTo(-18,19);ctx.closePath();ctx.fill();
 ctx.fillStyle="#ff4fd8";ctx.beginPath();ctx.moveTo(0,-13);ctx.lineTo(7,11);ctx.lineTo(-7,11);ctx.closePath();ctx.fill();
 ctx.shadowColor="#ff9a3d";ctx.fillStyle="#fff";ctx.beginPath();ctx.moveTo(-7,15);ctx.lineTo(0,35+Math.random()*9);ctx.lineTo(7,15);ctx.closePath();ctx.fill();ctx.restore();
}
function drawEnemy(e){
 ctx.save();ctx.translate(e.x,e.y);
 if(e.type==="boss"){ctx.rotate(Math.sin(e.age*.8)*.07);ctx.shadowBlur=28;ctx.shadowColor="#ff4fd8";ctx.fillStyle=`hsl(${305-e.stage*18} 65% 22%)`;ctx.beginPath();ctx.moveTo(0,-72);ctx.lineTo(96,-18);ctx.lineTo(65,60);ctx.lineTo(0,36);ctx.lineTo(-65,60);ctx.lineTo(-96,-18);ctx.closePath();ctx.fill();ctx.strokeStyle="#ff76df";ctx.lineWidth=5;ctx.stroke();ctx.fillStyle="#fff";ctx.beginPath();ctx.arc(0,-4,25,0,Math.PI*2);ctx.fill();ctx.fillStyle="#ff4fd8";ctx.beginPath();ctx.arc(0,-4,11,0,Math.PI*2);ctx.fill()}
 else{const c=e.type==="tank"?"#ff9a3d":e.type==="zig"?"#a873ff":"#55efff";ctx.shadowBlur=16;ctx.shadowColor=c;ctx.fillStyle=c;if(e.type==="tank"){ctx.beginPath();ctx.roundRect(-29,-24,58,48,12);ctx.fill();ctx.fillStyle="#fff";ctx.fillRect(-8,-31,16,24)}else{ctx.rotate(Math.PI);ctx.beginPath();ctx.moveTo(0,-24);ctx.lineTo(22,18);ctx.lineTo(0,8);ctx.lineTo(-22,18);ctx.closePath();ctx.fill();ctx.fillStyle="#fff";ctx.beginPath();ctx.arc(0,2,6,0,Math.PI*2);ctx.fill()}}
 ctx.restore();
}
function draw(){
 const bg=stageData[Math.max(0,stage-1)].bg,g=ctx.createLinearGradient(0,0,0,H);g.addColorStop(0,bg[0]);g.addColorStop(1,bg[1]);ctx.fillStyle=g;ctx.fillRect(0,0,W,H);
 ctx.save();if(shake>0)ctx.translate((Math.random()-.5)*shake,(Math.random()-.5)*shake);
 stars.forEach(s=>{ctx.globalAlpha=s.a;ctx.fillStyle="#fff";ctx.fillRect(s.x,s.y,s.z,s.z*3)});ctx.globalAlpha=1;
 for(const b of bullets){ctx.shadowBlur=15;ctx.shadowColor="#55efff";ctx.fillStyle="#efffff";ctx.fillRect(b.x-3,b.y-13,6,24)}ctx.shadowBlur=0;
 for(const b of enemyBullets){ctx.shadowBlur=14;ctx.shadowColor=b.color||"#ff4fd8";ctx.fillStyle=b.color||"#ff8ae7";ctx.beginPath();ctx.arc(b.x,b.y,b.r,0,Math.PI*2);ctx.fill()}ctx.shadowBlur=0;
 enemies.forEach(drawEnemy);
 powerups.forEach(p=>{ctx.save();ctx.translate(p.x,p.y);ctx.rotate(p.spin);ctx.shadowBlur=18;ctx.shadowColor="#ffe66d";ctx.fillStyle="#ffe66d";ctx.beginPath();for(let i=0;i<8;i++){const a=i*Math.PI/4,r=i%2?7:15;ctx.lineTo(Math.cos(a)*r,Math.sin(a)*r)}ctx.closePath();ctx.fill();ctx.restore()});
 particles.forEach(p=>{ctx.globalAlpha=Math.max(0,p.life/p.max);ctx.fillStyle=p.color;ctx.fillRect(p.x,p.y,p.size,p.size)});ctx.globalAlpha=1;
 if(!dead)drawShip();
 if(paused){ctx.fillStyle="#0009";ctx.fillRect(0,0,W,H);ctx.fillStyle="#fff";ctx.textAlign="center";ctx.font="bold 54px system-ui";ctx.fillText("PAUSE",W/2,H/2)}
 if(flash>0){ctx.globalAlpha=flash;ctx.fillStyle="#fff";ctx.fillRect(0,0,W,H);ctx.globalAlpha=1}
 ctx.restore();
}
function loop(now){if(!running)return;const dt=Math.min(.033,(now-last)/1000);last=now;if(!paused)update(dt);draw();if(running)requestAnimationFrame(loop)}
function setPointer(e){const r=canvas.getBoundingClientRect();player.x=(e.clientX-r.left)/r.width*W;player.y=(e.clientY-r.top)/r.height*H}
addEventListener("keydown",e=>{keys[e.key]=true;keys[e.key.toLowerCase()]=true;if(e.key.toLowerCase()==="p"&&running)paused=!paused;if(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"," "].includes(e.key))e.preventDefault()});
addEventListener("keyup",e=>{keys[e.key]=false;keys[e.key.toLowerCase()]=false});
canvas.addEventListener("pointerdown",e=>{pointer=true;setPointer(e)});canvas.addEventListener("pointermove",e=>{if(pointer)setPointer(e)});addEventListener("pointerup",()=>pointer=false);
document.querySelectorAll(".touch").forEach(b=>{const k=b.dataset.key;b.addEventListener("pointerdown",e=>{e.preventDefault();keys[k]=true});b.addEventListener("pointerup",()=>keys[k]=false);b.addEventListener("pointercancel",()=>keys[k]=false)});
document.getElementById("startBtn").addEventListener("click",begin);
highEl.textContent=String(high).padStart(7,"0");updateHUD();draw();
})();
</script>
</body>
</html>

投稿者: chosuke

趣味はゲームやアニメや漫画などです

「star_breaker_stg_stage5_power_barrage.html」への58件のフィードバック

  1. Эти платформы для совершеннолетних способны выступать инструментом сексуального ликбеза.
    Такие платформы дают возможность людям безопасно познавать свои предпочтения и фантазии.
    бесплатный эротический чат
    В отношениях общий просмотр способен становиться стимулом для доверительного диалога о желаниях.
    Кроме того подобные ресурсы позволяют уменьшать внутреннее напряжение и сохранять эмоциональное здоровье.

  2. Вручать подарки — это ценный способ выразить любовь и укрепить связь.
    Подарок позволяет близкому ощутить свою ценность для близких.
    Кроме того, дарение подарков укрепляет душевную близость между друзьями.
    Таким образом, искренний презент делает общение радостнее и поддерживает тёплые связи.
    https://autogrubin.ru/car-news/105-byudzhetnye-podarki-kotorye-kazhutsya-dorogimi-umnye-layfkhaki-i-kreativnye-resheniya/

  3. I began by reading the current case status so I knew where the case stood. A denial creates a different procedural situation, so I kept each procedural position in its own category. I left https://injuryclaimclarity.com/do-you-need-a-lawyer-to-file-form-rb-89/ under the matching case label so I could find the right procedural path again. The next thing I asked was why the Board left the case there. If the case was stuck at appeal, I read the review decision before thinking about another filing. For a case no longer set for hearing, I then asked what Board step was being requested. At that point I linked the procedural request to the reason the case needed action again. Occupational-disease cases can depend on repeated exposure instead of one direct trauma, because the proof may build across medical and work records. A later change in working ability can become a reopening fact when it is tied to new records. Whether someone uses a lawyer is different from why the review request was denied. The pattern I kept was: status first, reason second, what changed third, procedure last.

  4. Интернет-СМИ RFTimes является самостоятельную площадку, на которой выходят животрепещущие события из мира.
    Команда портала уделяет пристальное фокус качеству информации, предлагая читателям аналитику и эксклюзивные интервью.
    На сайте доступны свежие новости политики, и статьи про культуре и науке.
    Присоединяйтесь к наши обновлениям, дабы оставаться в курсе самых значимых событий.

  5. Флеш-накопитель на 2 гига и стильные флешки в подарок мужчине в Нальчике. Шоколадную плитку с нанесением логотипа цены и шопперы оптом в Владивостоке. USB Flash 128 ГБ и печать по флешке неподалёку в Костроме.
    https://usb-flashki-optom-24.ru/

  6. Сайты для взрослых существуют в качестве удобный способ изучить интимный развлечение без обязательных контактов и ненужного стресса.
    Такие сайты унижение чернокожие без смс открывают дискретный доступ к разным жанрам и позволяют пользователю самому определять подходящий режим просмотра.
    С позиции взрослой аудитории такой формат доступная опция расслабиться в одиночестве и не переходить посторонние границы.
    Нужно учитывать, что порносайты предназначены только для пользователей взрослых и призваны поддерживать правила безопасности и личного решения.

  7. Дом Rick Owens — это экспериментальный бренд, созданный в 94-м с нонконформистской идеей и особым подходом на границе мрачной эстетики и гранжа.
    Сам Оуэнс приобрёл известность скульптурными драпировками, асимметричными формами и применением кожи наряду с лаконичностью и мрачными цветами.
    rick-owens-moscow.ru
    Марка балансирует люкс и бунтарство, формируя одежду для тех, кто выбирает самовыражение и при этом не страшится выглядеть провокационно.
    На данный момент Rick Owens представляет собой больше чем одежда, но и полноценное мировоззрение, включающее мебель, обувь и подход продуманного бунтарства.

  8. XRumer является мощным инструментом для массовой создания учётных записей и постинга на блогах.
    Эта программа умеет преодолевать разные защиты, включая Captcha.
    Массовое использование веб-ресурсов даёт возможность стремительно увеличивать внешнюю ссылочную массу.
    Хрумер прогоны
    Большинство SEO-специалисты задействуют вышеупомянутый комплекс для раскрутки в сложных нишах.
    Функционирование с XRumer подразумевает сноровки и точных параметров.
    В противном случае есть риск получить санкции от поисковиков и падение ранжирования.
    Несмотря на опасности, популярность на такой софт держится значительным.

  9. Профессиональное обслуживание двухколёсной техники необходимо, так как от состояния его узлов во многом зависит управляемость в пути.
    Своевременный контроль даёт возможность избежать поломки и сохранить срок службы двигателя.
    https://integralmotors.ru
    Более того, правильное ТО поддерживает стоимость байка и помогает сделать поездки стабильнее.
    Поэтому не стоит экономить на техническом обслуживании, в противном случае попасть в дорогой ремонт.

  10. Responsible play refers to the balanced mindset toward online gambling that prioritizes control at the center.
    Responsible i-gaming teaches adults to set realistic budgets on spending and to schedule planned time-outs from gaming.
    https://forums.siliconera.com/threads/site-mis-en-avant.197057/
    It further strengthens self-awareness by supporting players to identify warning signs of risky gaming and to access assistance if required.
    Above all, responsible online gaming seeks to make gaming safe while remaining under personal control not letting betting grow into a source for financial strain.

  11. Films for adults are used like a means of consensual enjoyment aimed at adults.
    They provide an discreet setting for people to indulge in curiosity while ease tension within the legal context.
    https://asiansexhard.cc/
    Among adults, these movies often support open discussion around boundaries and work like one option for mutual enjoyment.
    The key is vital that this material are kept under ethical frameworks while protect safety so that such content serve as a responsible resource for consenting viewers.

  12. Дизайнер Рик Оуэнс воспринимается как среди наиболее узнаваемых дизайнеров нового поколения, что предложил собственный визуальный язык в духе готической эстетики и бунтарства.
    Рика Оуэнса стиль выделяется благодаря драпировкам, нестандартным силуэтам и любви к работе с текстурированной коже вместе с сдержанностью и глубокими цветами.
    rick-owens-boutique.ru
    Оуэнс приобрёл известность способностью соединять люкс и нонконформизм, предлагая одежду для ценит самовыражение при этом готов выглядеть иначе нестандартно.
    На данный момент этот дизайнер представляет собой не просто создатель коллекций, а также целое эстетическое высказывание, включающее мебельный дизайн, экстравагантную обувь и подход осознанного бунтарства.

  13. Металлический прокат выступает базой в машиностроения, поскольку гарантирует устойчивость объектов.
    Он масштабно востребован в строительстве сооружений, и при выпуске техники.
    Благодаря многообразию сортов прокат позволяет реализовывать масштабные архитектурные планы.
    металлобаза
    Кроме того металлопрокат востребован в выпуска промышленного оборудования а также многих сегментов промышленности.
    В результате прокат служит незаменимым ресурсом для надёжного роста строительства.

  14. При подборе строительной и складской погрузочной машины важно посмотреть прежде всего на задачи и требуемые параметры оборудования.
    После этого нужно проверить техническое состояние, грузоподъёмность, удобство управления и наличие расходников.
    Также нужно проверить расходы на эксплуатацию, условия сервиса, репутацию поставщика и отзывы других компаний.
    Больше подборку можно найти по ссылке https://www.dobrepole.com.ua/forum/54-13514-1.

  15. Программа XRumer считается раскрученным программным комплексом для автоматизированной регистрации и постинга на блогах.
    Он умеет обходить разные защиты, в том числе Captcha.
    Массовое использование площадок обеспечивает оперативно набирать внешнюю ссылочную массу.
    t.me/xrumer24
    Многие SEO-специалисты используют вышеупомянутый инструмент для продвижения в сложных нишах.
    Функционирование с софтом XRumer предполагает опыта и точных параметров.
    В противном случае есть риск получить блокировку от поисковиков и падение позиций.
    Несмотря на все минусы, спрос на такой софт держится высоким.

  16. It is refreshing to read something that is just direct and helpful, without any unnecessary fluff, and I wanted to make sure I left a comment to acknowledge the solid effort that went into producing this written material.

    top canadian online casinos

  17. Дом моды Rick Owens — это авангардный проект, запущенный более тридцати лет назад с антигламурной идеей и узнаваемым подходом в духе тёмного гламура и бунтарства.
    Рик Оуэнс прославился объёмными драпировками, асимметричными формами и применением текстурированных материалов в сочетании с лаконичностью и мрачными оттенками.
    Бренд балансирует роскошь и бунтарство, предлагая одежду для тех, кто ценит уникальность и готов выделяться нестандартно.
    Рик Овенс коллекция
    Сегодня Rick Owens является уже не только одежда, а целое эстетическое высказывание, охватывающее предметы интерьера, экстравагантную обувь и идеологию осознанного нонконформизма.
    Бренд служит влиятельным голосом в индустрии, задаёт смелые тренды и обладает культовой армией поклонников.

  18. Сфера туризма служит мощным двигателем хозяйственного развития, формируя новые рабочие места и стимулируя инвестиции.
    Туристическая деятельность благоприятствует цивилизационному диалогу и взаимопониманию между людьми.
    https://www.intensedebate.com/people/IvanErmilov92
    Индустрия туризма поддерживает развитие сервиса и совершенствует качество среды в регионах.
    Поездки обеспечивают шанс для интеллектуального обогащения, просвещения и обогащения знаний.

  19. Odpovědné hraní představuje vyvážený přístup a rámec k i-gamingu, jenž klade na první místo bezpečnost a blaho účastníka.
    Vede uživatele, aby si stanovili osobní limity na trávený čas a plánovali včasné časové pauzy od hraní.
    https://zahonyakompostery.cz/
    Také zvyšuje transparentnost a pomáhá hráčům identifikovat rané signály škodlivého sázení a pokud je to nutné získat pomoc.
    Účelem zodpovědného i-gamingu je zajistit, aby hraní zůstalo i nadále příjemnou zábavou v rámci uživatelových limitů a osobní kontroly, a nestalo se příčinou stresu.

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です