激光钢琴手感修正:降速/扫射安全区/蓄力前摇/键距统一/舰桥随壳裂开

- 降速:mainT2->4、单键hotT1->2/ks.t(1/1)->(2/3)、齐射hotT4->6、模式间隔(8/14)->(14/22),密度609->约135束/10s
- 顺扫止于18号键/反扫止于3号键:尽头3键永不发射,玩家总有躲藏区
- 前摇动画:即将发射的琴键下方画圆形蓄力圈(随hotT进度放大变亮)
- 键距9.5->10整数化:消除取整导致的'两个一组'视觉;光束kx计算同步
- 舰桥从中线剖开两半各随半壳平移(原来整体跟左壳跑);壳沿铆钉同步分半
This commit is contained in:
JOJO 2026-08-05 21:38:23 +08:00
parent d821d6d32e
commit 1d4e8597bb
2 changed files with 24 additions and 12 deletions

View File

@ -303,24 +303,24 @@ function bossMain(b,def,fm){
const ks=b.keys,n=ks.n;
if(ks.hotT>0){ks.hotT--;
if(ks.hotT===0){const list=ks.hotList||[ks.hot];
for(const kh of list){if(kh<0)continue;const kx=-(n-1)*4.75+kh*9.5;
for(const kh of list){if(kh<0)continue;const kx=-(n-1)*5+kh*10; // 与drawPiano键位一致整数键距10
bossBeam(b.x+kx,b.y+18,b.x+kx,H+8,4,"#43e8ff",7,22,18,{b,ox:kx,oy:18,followX2:true});}
ks.hotList=null;ks.hot=-1;SFX.eshoot();}}
ks.t--;
if(ks.t<=0&&ks.hotT<=0){
if(ks.i>=ks.seq.length){ // 布下一局:轮换模式
ks.mode=(ks.mode+1)%4;
if(ks.mode===0){ks.seq=[];for(let i=0;i<n;i++)ks.seq.push(i);}
else if(ks.mode===1){ks.seq=[];for(let i=n-1;i>=0;i--)ks.seq.push(i);}
if(ks.mode===0){ks.seq=[];for(let i=0;i<n-3;i++)ks.seq.push(i);} // 顺扫止于18号最右3键永远安全
else if(ks.mode===1){ks.seq=[];for(let i=n-1;i>=3;i--)ks.seq.push(i);} // 反扫止于3号最左3键永远安全
else if(ks.mode===2){ks.seq=shuffled(n);}
else{ks.seq=[];for(let i=0;i<6+ph*2;i++)ks.seq.push(-1);} // -1=齐射标记
ks.i=0;ks.t=Math.round((ph?8:14)/fm); // 光速进入下一种模式
ks.i=0;ks.t=Math.round((ph?14:22)/fm);
}else{const cur=ks.seq[ks.i++];
if(cur===-1){const pool=shuffled(n);ks.hotList=pool.slice(0,4+ph*2);ks.hotT=4;ks.t=Math.round((ph?8:12)/fm);}
else{ks.hot=cur;ks.hotT=1;ks.t=Math.round((ph?1:1)/fm);} // 扫射模式每tick一键≈5倍速)
if(cur===-1){const pool=shuffled(n);ks.hotList=pool.slice(0,4+ph*2);ks.hotT=6;ks.hotT0=6;ks.t=Math.round((ph?14:20)/fm);}
else{ks.hot=cur;ks.hotT=2;ks.hotT0=2;ks.t=Math.round((ph?2:3)/fm);} // 扫射模式(整体已降速)
}
}
b.mainT=2;break;}
b.mainT=4;break;}
case "hive": // 母巢核心:环弹+孵化
for(let i=0;i<10+ph*4;i++)ebul(b.x,b.y,i/(10+ph*4)*TAU+b.t*0.03,1.6+0.2*ph,"orbO");
if(b.t%240<3)for(let i=0;i<1+ph;i++)spawnEnemy(ph>=2?"kami":"mini",b.x+rnd(-30,30),b.y+8,false);

View File

@ -228,11 +228,19 @@ function drawAssault(t,fl,swp,ph,mp){ // 暗黑突击swp=翼展角;炮管/
}
function drawPiano(b,t,fl,split){ // 激光钢琴split=裂壳进度0~1
const ks=b.keys,n=ks?ks.n:21;
px(-(n-1)*4.75-5,6,(n-1)*9.5+10,19,"#141821"); // 键槽
for(let i=0;i<n;i++){const kx=-(n-1)*4.75+i*9.5;
px(-(n-1)*5-5,6,(n-1)*10+10,19,"#141821"); // 键槽键距10统一不再因非整数取整成对
for(let i=0;i<n;i++){const kx=-(n-1)*5+i*10;
const hot=ks&&(ks.hot===i||(ks.hotList&&ks.hotList.indexOf(i)>=0));
px(kx-4,8,8,14,hot?(t%6<3?"#e8fbff":"#43e8ff"):"#d8e4f0");
px(kx-4,20,8,2,hot?"#43e8ff":"#8a9ab8");}
if(ks&&ks.hotT>0&&ks.hotT0){const pr=1-ks.hotT/ks.hotT0; // 蓄力前摇:即将发射的键下方圆形蓄力
const list=ks.hotList||(ks.hot>=0?[ks.hot]:[]);
for(const kh of list){const kx=-(n-1)*5+kh*10;
ctx.globalAlpha=0.3+0.55*pr;ctx.strokeStyle="#43e8ff";ctx.lineWidth=1.5;
ctx.beginPath();ctx.arc(kx,28,2+3.5*pr,0,TAU);ctx.stroke();
ctx.globalAlpha=0.22*pr;ctx.fillStyle="#43e8ff";
ctx.beginPath();ctx.arc(kx,28,2+3.5*pr,0,TAU);ctx.fill();
ctx.globalAlpha=1;}}
const off=split*30; // 两半穹顶向左右裂开
for(const sd of[-1,1]){ctx.save();ctx.translate(sd*off,0);
const q0=sd<0?Math.PI:Math.PI*1.5,q1=sd<0?Math.PI*1.5:Math.PI*2;
@ -247,9 +255,13 @@ function drawPiano(b,t,fl,split){ // 激光钢琴split=裂壳进度0~1
if(split<1){ctx.globalAlpha=1-split; // 一阶段青色核心窗
px(-7,-14,14,9,fl||"#43e8ff");px(-4,-12,8,5,"#bfefff");
ctx.globalAlpha=1;}
px(-10-off,-32,20,10,"#3a4460");px(-6-off,-37,12,5,"#55648a"); // 舰桥随左半壳
if(split<0.4)for(let i=0;i<7;i++){const a=Math.PI+(i+0.5)/7*Math.PI;
px(Math.cos(a)*110-1.5,6+Math.sin(a)*30-1.5,3,3,"#9fb4d8");}
for(const sd of[-1,1]){ctx.save();ctx.translate(sd*off,0); // 舰桥从中线剖开,各随各的半壳
px(sd<0?-10:0,-32,10,10,"#3a4460");
px(sd<0?-6:0,-37,6,5,"#55648a");
for(let i=0;i<7;i++){const a=Math.PI+(i+0.5)/7*Math.PI; // 壳沿铆钉也随半壳
if((sd<0)!==(a<Math.PI*1.5))continue;
px(Math.cos(a)*110-1.5,6+Math.sin(a)*30-1.5,3,3,"#9fb4d8");}
ctx.restore();}
}
/* ---- Boss光束与浮游炮渲染 ---- */
function drawFunnel(f){ // 蓝白长钉无人机(单架)