diff --git a/star-raid/css/style.css b/star-raid/css/style.css index 6a293e5..ea56c9c 100644 --- a/star-raid/css/style.css +++ b/star-raid/css/style.css @@ -52,6 +52,9 @@ h1.logo{font-size:clamp(20px,5.4vw,44px);color:#fff;letter-spacing:4px;line-heig .stat-grid b{color:var(--gold);text-align:right} /* ship / mode select cards */ .pick{display:flex;gap:10px;flex-wrap:wrap;justify-content:center} +.rush-grp{width:100%;margin:2px 0 10px} +.rush-grp .h3{font-size:clamp(9px,1.6vw,12px);letter-spacing:3px;margin-bottom:5px} +.rush-row{display:flex;gap:10px;flex-wrap:wrap;justify-content:center} .pcard{width:min(28vw,132px);background:var(--panel);border:3px solid var(--line);padding:10px 6px;cursor:pointer;transition:all .12s} .pcard:hover{transform:translateY(-3px)} .pcard.sel{border-color:var(--cyan);box-shadow:0 0 16px rgba(65,230,255,.35)} diff --git a/star-raid/js/enemies.js b/star-raid/js/enemies.js index 277dbc4..5a57faf 100644 --- a/star-raid/js/enemies.js +++ b/star-raid/js/enemies.js @@ -188,17 +188,18 @@ function updateSpawner(){ } /* ================= Boss 战 ================= */ /* 8大Boss:1种主攻击模式 + 同时1~2种随机小攻击;血量阈值触发二/三阶段变形 */ +/* 难度tier:0简单/1中等/2困难/3地狱(rush界面分组;用户2026-08-06分级) */ const BOSSES=[ - {name:"巡逻巡洋舰",sub:"PATROL CRUISER",hp:950,col:"#e0393e",r:22,main:"cruiser",minors:["snipe","ring"],phases:2}, - {name:"太空原种",sub:"SPACE SPAWN",hp:1350,col:"#ff8fc8",r:20,rr:[20,34],ryy:[26,18],wide:1,main:"spawn",minors:["wiggle","spikeSnipe","sporeArc","tentBeam","mawSnipe","wingRain"],phases:2}, - {name:"歼灭者",sub:"ANNIHILATOR",hp:1700,col:"#b05ce8",r:22,main:"annihilate",minors:["aimSpread","spawnMine"],phases:3}, - {name:"暗黑突击",sub:"DARK ASSAULT",hp:2100,col:"#ff3355",r:9,rr:[9,10,11],ryy:[5,6,7],main:"assault",minors:["rain","aimSpread"],phases:3}, - {name:"激光钢琴",sub:"LASER PIANO",hp:5000,col:"#43e8ff",r:26,rr:[100,100],ryy:[30,30],main:"piano",minors:["topRain","pedal"],phases:2,static:1}, - {name:"母巢核心",sub:"HIVE CORE",hp:2800,col:"#ff9a3d",r:22,main:"hive",minors:["spawnMini","aimSpread","ring"],phases:3}, - {name:"夺权者X",sub:"USURPER X",hp:3700,col:"#e8f4ff",r:24,rr:[58,26],ryy:[34,40],wide:1,main:"usurper",minors:["deckVolley","pillar","aimSpread"],phases:2}, - {name:"暗黑魔碟",sub:"DARK SAUCER",hp:4500,col:"#8a5cff",r:24,rr:[30,32,34],main:"saucer",minors:["ringBig","coneFan","crossEye","dartSpiral"],phases:3}, - {name:"黑石要塞",sub:"BLACKSTONE",hp:3400,col:"#5cff9d",r:30,rr:[34,37],ryy:[26,28],wide:1,main:"blackstone",minors:["deckGuns","crackRift","starLine"],phases:2}, - {name:"泰伦虫族母舰",sub:"TYRANID HIVESHIP",hp:3200,col:"#7dff8a",r:26,rr:[26,29,32],ryy:[36,38,40],main:"hivespawn",minors:["sporeBloom","tentSweep","acidGas"],phases:3} + {name:"巡逻巡洋舰",sub:"PATROL CRUISER",hp:950,col:"#e0393e",r:22,main:"cruiser",minors:["snipe","ring"],phases:2,tier:0}, + {name:"太空原种",sub:"SPACE SPAWN",hp:1350,col:"#ff8fc8",r:20,rr:[20,34],ryy:[26,18],wide:1,main:"spawn",minors:["wiggle","spikeSnipe","sporeArc","tentBeam","mawSnipe","wingRain"],phases:2,tier:1}, + {name:"歼灭者",sub:"ANNIHILATOR",hp:1700,col:"#b05ce8",r:22,main:"annihilate",minors:["aimSpread","spawnMine"],phases:3,tier:0}, + {name:"暗黑突击",sub:"DARK ASSAULT",hp:2100,col:"#ff3355",r:9,rr:[9,10,11],ryy:[5,6,7],main:"assault",minors:["rain","aimSpread"],phases:3,tier:2}, + {name:"激光钢琴",sub:"LASER PIANO",hp:5000,col:"#43e8ff",r:26,rr:[100,100],ryy:[30,30],main:"piano",minors:["topRain","pedal"],phases:2,static:1,tier:2}, + {name:"母巢核心",sub:"HIVE CORE",hp:2800,col:"#ff9a3d",r:22,main:"hive",minors:["spawnMini","aimSpread","ring"],phases:3,tier:0}, + {name:"夺权者X",sub:"USURPER X",hp:3700,col:"#e8f4ff",r:24,rr:[58,26],ryy:[34,40],wide:1,main:"usurper",minors:["deckVolley","pillar","aimSpread"],phases:2,tier:2}, + {name:"暗黑魔碟",sub:"DARK SAUCER",hp:4500,col:"#8a5cff",r:24,rr:[30,32,34],main:"saucer",minors:["coneFan","crossEye","dartSpiral"],phases:3,tier:3}, // 间歇期无圆圈弹幕(去ringBig,P3主攻击仍两层) + {name:"黑石要塞",sub:"BLACKSTONE",hp:3400,col:"#5cff9d",r:30,rr:[34,37],ryy:[26,28],wide:1,main:"blackstone",minors:["deckGuns","crackRift","starLine"],phases:2,tier:2}, + {name:"泰伦虫族母舰",sub:"TYRANID HIVESHIP",hp:3200,col:"#7dff8a",r:26,rr:[26,29,32],ryy:[36,38,40],main:"hivespawn",minors:["sporeBloom","tentSweep","acidGas"],phases:3,tier:1} ]; /* Boss命中判定:支持椭圆(宽扁机型),rr=x半径,ry=y半径 */ function bossHit(x,y,r){ @@ -265,6 +266,7 @@ function startBoss(){ col:b.col,name:b.name,sub:b.sub,fireM:BAL.fireMul(n)*(G.diff===1?BAL.hard.fire:1),dead:false, mainT:100,minorT:9999,minorSet:[],rerollT:340,ax:W/2,ay:64,mt:0,landed:false}; if(b.main==="piano")G.boss.mainT=24; // 激光钢琴:缩短开局空窗 + else if(b.main==="assault")G.boss.mainT=rndi(240,900); // 暗黑突击:首次冲撞4~15秒随机 G.bossN++;SFX.warn();MUS.start(true); banner("WARNING — "+b.name,"#ff5566",150); } @@ -281,26 +283,31 @@ function updateBoss(){ G.eb.length=0;G.bbeams.length=0;b.keys=null;SFX.warn();G.shake=Math.max(G.shake,5); if(b.idx===6){G.funnels.length=0;b.form=null;if(np===1){spawnFunnels(b,4);b.plT=Math.round(300/b.fireM);}} // 夺权者X二阶段:增至4架僚机 banner(b.name+" — 第"+["一","二","三"][np]+"形态","#ff5566",90);} - if(b.transT>0){b.transT--; + if(b.transT>0){b.transT--;b.dashTrail=null; // 变形期间清冲撞残影 if(b.transT===0){explodeFx(b.x,b.y,"dark",1.3);G.shake=Math.max(G.shake,6); for(let i=0;i<10;i++)ebul(b.x,b.y,i/10*TAU,1.5,"orbP",12);} // 变形完成爆发环弹 updateFunnels();return;} // 变形期间不攻击 // —— 冲撞状态机(暗黑突击) —— if(b.dashSt){ const ds=b.dashSt; - if(ds.ph==="tele"){ds.t--; + if(ds.ph==="tele"){b.dashTrail=null;ds.t--; if(ds.t<=0){const ap3=aimPt(),a=Math.atan2(ap3.y-b.y,ap3.x-b.x); - ds.ph="go";ds.t=85;ds.vx=Math.cos(a)*7.2;ds.vy=Math.sin(a)*7.2;SFX.warn();}} + ds.ph="go";ds.t=85;ds.vx=Math.cos(a)*(b.phase>=2?10.8:7.2);ds.vy=Math.sin(a)*(b.phase>=2?10.8:7.2);SFX.warn();}} // 三阶段冲撞速度150% else if(ds.ph==="go"){b.x+=ds.vx;b.y+=ds.vy;ds.t--; + if(b.phase>=1){b.dashTrail=b.dashTrail||[];b.dashTrail.push({x:b.x,y:b.y});if(b.dashTrail.length>7)b.dashTrail.shift();} // 二三阶段:冲锋红色残影 if(G.time%9===0){const a5=Math.atan2(aimPt().y-b.y,aimPt().x-b.x);ebul(b.x,b.y,a5,2.7,"orbR",13);} // 冲撞途中瞄准弹 - if(ds.t<=0||b.y>H+26||b.y<-46||b.x<-26||b.x>W+26){ds.ph="back";ds.t=160;}} - else{b.x+=(b.ax-b.x)*0.045;b.y+=(b.ay-b.y)*0.045;ds.t--; - if(ds.t<=0||(Math.abs(b.x-b.ax)<5&&Math.abs(b.y-b.ay)<5)){b.dashSt=null;b.mainT=Math.round(105/b.fireM);}} // 冲撞间隔+50% + if(ds.t<=0||b.y>H+26||b.y<-46||b.x<-26||b.x>W+26){ds.ph="back";ds.t=b.phase>=2?90:160;}} + else{b.dashTrail=null; + const k2=b.phase>=2?0.12:0.045; // 三阶段回位更快=惯性更小 + b.x+=(b.ax-b.x)*k2;b.y+=(b.ay-b.y)*k2;ds.t--; + if(ds.t<=0||(Math.abs(b.x-b.ax)<5&&Math.abs(b.y-b.ay)<5)){b.dashSt=null;b.mainT=rndi(240,900);}} // 冲撞间隔4~15秒随机 updateFunnels();return; } // —— 常规移动 —— if(def.static){b.x+=(W/2-b.x)*0.05;b.y+=(52-b.y)*0.02;} - else if(b.idx===3){b.x=W/2+Math.sin(b.mt*0.034)*62;b.y=b.ty+Math.sin(b.mt*0.021)*18;} // 暗黑突击:小体型高机动(空闲大幅提速) + else if(b.idx===3){ // 暗黑突击:小体型高机动;三阶段更快+上下范围更大+惯性更小(速度积分,转折锐利) + if(b.phase>=2){b.x=clamp(b.x+62*0.052*Math.cos(b.mt*0.052),26,W-26);b.y=b.ty+Math.sin(b.mt*0.03)*27;} + else{b.x=W/2+Math.sin(b.mt*0.034)*62;b.y=b.ty+Math.sin(b.mt*0.021)*18;}} else if(b.idx===6){const usp=b.phase>=1?0.028:0.008,amp=b.phase>=1?70:44; b.x=clamp(b.x+amp*usp*Math.cos(b.mt*usp),30,W-30); // 速度积分定位:换阶段参数突变也不瞬移 b.yA=(b.yA||8)+((b.phase>=1?12:8)-(b.yA||8))*0.05;b.y=b.ty+Math.sin(b.mt*0.011)*b.yA;} // 夺权者X:P1巨大笨重→P2紧凑灵活 @@ -318,7 +325,7 @@ function updateBoss(){ else{ if(b.plT===142){b.laserT=142;b.warpChg=0.001;SFX.warn();} if(b.plT<=142&&b.plT>90)b.warpChg=Math.min(1,(142-b.plT)/52); - if(b.plT===90){b.warpChg=0;bossBeam(b.x,b.y+6,b.x,H+8,b.phase>=1?24:20,"#5cff9d",10,80,30,{b,ox:0,oy:6,followX2:true,sweep:1,amp:b.phase>=1?70:50});} + if(b.plT===90){b.warpChg=0;bossBeam(b.x,b.y+6,b.x,H+8,b.phase>=1?24:20,"#5cff9d",10,80,99999,{b,ox:0,oy:6,followX2:true,sweep:1,amp:b.phase>=1?70:50});} // 亚空间主炮:99999伤害 } } if(b.idx===9){ // 泰伦触手扫击:9秒一次左右随机 + 玩家靠近立即触发对应侧 @@ -334,7 +341,7 @@ function updateBoss(){ for(let i=1;i<7;i++){const f=i/6,sr=3.2*(1-f*0.45)+G.stat.hitR+1; const ax=pts[i-1].x,ay=pts[i-1].y,dx=pts[i].x-ax,dy=pts[i].y-ay,L2=dx*dx+dy*dy||1; const tt=clamp(((lx-ax)*dx+(ly-ay)*dy)/L2,0,1),cx=ax+dx*tt,cy=ay+dy*tt; - if(dist2(lx,ly,cx,cy)0){ks.hotT--; @@ -392,8 +399,8 @@ function bossMain(b,def,fm){ ks.hotList=null;ks.hot=-1;SFX.eshoot();}} ks.t--; if(ks.t<=0&&ks.hotT<=0){ - if(ks.i>=ks.seq.length){ // 布下一局:轮换模式(5种) - ks.mode=(ks.mode+1)%5; + if(ks.i>=ks.seq.length){ // 布下一局:随机抽模式(5种) + ks.mode=rndi(0,5); if(ks.mode===0){ks.seq=[];for(let i=0;i=3;i--)ks.seq.push(i);} // 反扫止于3号:最左3键永远安全 else if(ks.mode===2){ks.seq=shuffled(n);} @@ -439,7 +446,7 @@ function bossMain(b,def,fm){ ebul(px2,py2,a6,4.4,"dartS",15);} // 发射点=最下甲板炮口(与drawUsurper同源) b.mainT=Math.round(46/fm); }else{ - if(!b.plT||b.plT<=0){bossBeam(b.x,b.y+20,b.x,H+8,22,"#7ce9ff",46,80,30,{b,ox:0,oy:20,followX2:true}); + if(!b.plT||b.plT<=0){bossBeam(b.x,b.y+20,b.x,H+8,22,"#7ce9ff",46,80,99999,{b,ox:0,oy:20,followX2:true}); // 巨宽核心激光:99999伤害 b.laserT=130;b.plT=Math.round(420/fm);b.mainT=40;SFX.warn();} else{for(let k=-1;k<=1;k++)ebul(b.x,b.y+30,a0+k*0.14,4.4,"dartS",16); b.mainT=Math.round(88/fm);} @@ -456,7 +463,7 @@ function bossMain(b,def,fm){ b.mainT=Math.round((ph>=2?24:ph===1?30:36)/fm); if(ph>=1&&(!b.eyeT||b.eyeT<=0)){const ex=ap2.x; for(const sd of[-1,1])bossBeam(b.x+sd*9,b.y-3,ex+sd*6,H+8,4,"#ff3355",22,26,20,{b,ox:sd*9,oy:-3}); - b.eyeT=Math.round(150/fm);} + b.eyeT=Math.round(300/fm);} // 二阶段激光间隔翻倍(150→300);三阶段不变 if(ph>=2&&b.hornT<=0){const sd=(b.hornSide=(b.hornSide||1)*-1); const hx=b.x+sd*41,hy=b.y-33,ha=Math.atan2(ap2.y-hy,ap2.x-hx); for(let k=-1;k<=1;k++)ebul(hx,hy,ha+k*0.16,2.8,"orbR",15); diff --git a/star-raid/js/render.js b/star-raid/js/render.js index 2ff7fb4..a1d27f0 100644 --- a/star-raid/js/render.js +++ b/star-raid/js/render.js @@ -36,6 +36,12 @@ function poly(pts,col){ctx.fillStyle=col;ctx.beginPath();ctx.moveTo(pts[0],pts[1 function circ(x,y,r,col){ctx.fillStyle=col;ctx.beginPath();ctx.arc(x,y,r,0,TAU);ctx.fill();} function drawBoss(){ const b=G.boss;if(!b)return; + // 暗黑突击冲撞红色残影(二三阶段冲刺时记录位置,旧→新淡出;先画在机体下方) + if(b.idx===3&&b.dashTrail&&b.dashTrail.length){ + for(let i=0;i0){const prog=1-b.transT/70; @@ -184,7 +190,7 @@ function drawBoss(){ if(ctx.setLineDash)ctx.setLineDash([4,3]); ctx.beginPath();ctx.moveTo(b.x,b.y);ctx.lineTo(G.p.x,G.p.y);ctx.stroke(); if(ctx.setLineDash)ctx.setLineDash([]);ctx.globalAlpha=1;} - // 多管血条:一管蓝/二管红/三管橙,当前管铺在下一管之上,见底锁血转场 + // 多管血条:一管蓝/二管红/三管橙,当前管铺在下一管之上,见底锁血转场(不画管界刻痕=整管连续无切段) const w=160,def2=BOSSES[b.idx],thr=def2.phases===2?[0.5]:[0.66,0.33]; const TUBEC=["#43b8ff","#e0393e","#ff9a3d"]; const ratio=clamp(b.hp/b.maxhp,0,1),bx=(W-w)/2; @@ -192,8 +198,7 @@ function drawBoss(){ px(bx,10,w,4,b.phase0&&G.time%8<4){ctx.strokeStyle="#fff";ctx.lineWidth=1;ctx.strokeRect(bx-2.5,7.5,w+5,9);} ctx.font="6px 'Press Start 2P',monospace";ctx.fillStyle="#fff";ctx.textAlign="center"; ctx.fillText(b.transT>0?b.name:(b.name+" "+Math.ceil(pc*100)+"%"),W/2,22); diff --git a/star-raid/js/ui.js b/star-raid/js/ui.js index e6e081c..dbf1c69 100644 --- a/star-raid/js/ui.js +++ b/star-raid/js/ui.js @@ -340,15 +340,24 @@ function buildRush(){ SAVE.rush=SAVE.rush||{}; const ra=$("rush-anim"); // 老虎机开关(持久化) if(ra){ra.checked=!!SAVE.rushAnim;ra.onchange=()=>{SAVE.rushAnim=ra.checked?1:0;persist();};} + // 按难度分级分组展示(BOSSES[i].tier:0简单/1中等/2困难/3地狱) + const TIERS=[["简单","#5cff9d"],["中等","#ffcf5c"],["困难","#ff9a3d"],["地狱","#ff3355"]]; const el=$("rush-pick");el.innerHTML=""; - BOSSES.forEach((b,i)=>{ - const best=SAVE.rush[i]; - const d=document.createElement("div");d.className="pcard"; - d.innerHTML=`
${b.name}${best?" ✓":""}
-
${b.sub}
${best?("最快 "+Math.floor(best/60)+":"+("0"+best%60).slice(-2)):"未击破"}
`; - d.onclick=()=>startRush(i); - el.appendChild(d); - }); + for(let ti=0;ti<4;ti++){ + const grp=document.createElement("div");grp.className="rush-grp"; + grp.innerHTML=`
— ${TIERS[ti][0]} —
`; + const row=document.createElement("div");row.className="rush-row"; + BOSSES.forEach((b,i)=>{ + if(b.tier!==ti)return; + const best=SAVE.rush[i]; + const d=document.createElement("div");d.className="pcard"; + d.innerHTML=`
${b.name}${best?" ✓":""}
+
${b.sub}
${best?("最快 "+Math.floor(best/60)+":"+("0"+best%60).slice(-2)):"未击破"}
`; + d.onclick=()=>startRush(i); + row.appendChild(d); + }); + if(row.children.length){grp.appendChild(row);el.appendChild(grp);} + } } function rollRushBuild(){ // 随机武装:3主武Lv3 + 3副武Lv3 + 2僚机Lv2 const sh=a=>{const x=a.slice();for(let i=x.length-1;i>0;i--){const j=rndi(0,i),t2=x[i];x[i]=x[j];x[j]=t2;}return x;};