- 大激光矩形上边加向上凸起的半圆(arc Math.PI→0),直径=激光宽度,像枪口扩口 - 左右大炮塔外观全改红色(装甲#5a1a1a/#8a2a2a,指示灯#ff3355) - 从钢琴minors去掉pedal,大炮塔不再发射小攻击子弹,只保留大激光惩罚+topRain
322 lines
22 KiB
JavaScript
322 lines
22 KiB
JavaScript
"use strict";
|
||
/* ================= Boss 美术库(大改重设计) =================
|
||
激光钢琴 drawPiano / 夺权者X drawUsurper / 暗黑魔碟 drawSaucer
|
||
设计标准见 .astrion/memory/boss_design_standard.md:
|
||
大剪影+3~4层配色递进+多层结构+受光逻辑+发光焦点+微动效;变形=同一几何体连续演化 */
|
||
/* ---- 激光钢琴:穹顶琴键要塞(split=裂壳进度0~1) ----
|
||
4层同心装甲环带+像素琴键炮口带;变形=环带沿中线阶梯滑开(内层滑更远)露红色管线网+红核 */
|
||
function drawPiano(b,t,fl,split){
|
||
const ks=b.keys,n=ks?ks.n:21;
|
||
// —— 红色管线网(壳下常存,裂壳才见;锯齿线非圆) ——
|
||
if(split>0){ctx.globalAlpha=split*0.85;
|
||
for(let k=0;k<5;k++){const lx=-40+k*20;
|
||
px(lx,-14,1,10,"#ff3355");px(lx,-5,4,1,"#ff3355");px(lx+3,-4,1,8,"#ff3355");}
|
||
ctx.globalAlpha=1;}
|
||
// —— 红色核心(裂壳显现,搏动;收在穹顶基线之上) ——
|
||
if(split>0){ctx.globalAlpha=split;
|
||
const cr=8+Math.sin(t*0.12)*1.5;
|
||
circ(0,-8,cr+4,"#7a0e1e");circ(0,-8,cr,fl||"#ff3355");circ(0,-8,cr*0.45,"#ffdfe5");
|
||
ctx.globalAlpha=1;}
|
||
if(split<1){ctx.globalAlpha=1-split; // 一阶段青色核心窗
|
||
px(-7,-14,14,9,fl||"#43e8ff");px(-4,-12,8,5,"#bfefff");
|
||
ctx.globalAlpha=1;}
|
||
// —— 穹顶4层装甲环带(沿中线剖半;内层滑得更远=阶梯裂口) ——
|
||
const BANDS=[[118,34,"#10151f"],[98,28,"#1b2434"],[74,21,"#33436a"],[50,14,"#55648a"]];
|
||
for(let bi=0;bi<4;bi++){const off=split*(16+bi*6),rx=BANDS[bi][0],ry=BANDS[bi][1];
|
||
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;
|
||
ctx.fillStyle=BANDS[bi][2];ctx.beginPath();ctx.ellipse(0,6,rx,ry,0,q0,q1);ctx.lineTo(0,6);ctx.closePath();ctx.fill();
|
||
ctx.restore();}}
|
||
// —— 外环窗火+壳沿铆钉(随最外半壳滑开) ——
|
||
for(const sd of[-1,1]){ctx.save();ctx.translate(sd*split*16,0);
|
||
for(let k=0;k<4;k++)px(sd*(20+k*22)-2,-2,4,3,t%40<20?"#3d5a73":"#24304a"); // 窗火明暗
|
||
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();}
|
||
// —— 6座穹顶小炮塔(topRain炮位,与enemies.js同源:x=-75+ti*30,P2随第3环带滑开28) ——
|
||
{const off2=split*28;
|
||
for(let ti=0;ti<6;ti++){const sd2=ti<3?-1:1,tx=-75+ti*30+sd2*off2;
|
||
circ(tx,-4,3.5,"#33436a");circ(tx-1,-5,1.5,"#55648a");
|
||
px(tx-1,-2,2,5,b.turrT>0&&((b.turrIs&&b.turrIs.includes(ti))||b.turrI===ti)?"#e8fbff":"#1b2434");}}
|
||
// —— 左右大炮塔(踏板重音炮位;左紫右蓝;P2随最外环带滑开16) ——
|
||
{const off0=split*16;
|
||
for(const sd of[-1,1]){const px2=sd*(112+off0);
|
||
circ(px2,2,5.5,"#5a1a1a");circ(px2-1.5,0,2.5,"#8a2a2a");
|
||
px(px2-1.5,4,3,8,"#1b2434");
|
||
px(px2-1,10,2,3,"#ff3355");
|
||
// 大激光蓄力前摇:画在炮塔口下方的蓄力圆(与小激光琴键蓄力圆同源,换色赤红)
|
||
const prog=sd<0?((b.pedLasL||0)/60):((b.pedLasR||0)/60);
|
||
if(prog>0){const a=Math.min(prog,1);
|
||
ctx.globalAlpha=0.3+0.55*a;ctx.strokeStyle="#ff3355";ctx.lineWidth=1.5;
|
||
ctx.beginPath();ctx.arc(px2,14,2+3.5*a,0,TAU);ctx.stroke();
|
||
ctx.globalAlpha=0.22*a;ctx.fillStyle="#ff3355";
|
||
ctx.beginPath();ctx.arc(px2,14,2+3.5*a,0,TAU);ctx.fill();
|
||
ctx.globalAlpha=1;}}}
|
||
// —— 舰桥+雷达(随半壳滑开) ——
|
||
for(const sd of[-1,1]){ctx.save();ctx.translate(sd*split*30,0);
|
||
px(sd<0?-10:0,-32,10,10,"#1b2434");
|
||
px(sd<0?-6:0,-37,6,5,"#33436a");
|
||
ctx.restore();}
|
||
ctx.save();ctx.translate(-split*30,0); // 雷达随左半壳
|
||
circ(0,-34,4,"#33436a");
|
||
drawSeg(0,-34,Math.cos(t*0.05)*8,-34+Math.sin(t*0.05)*8,1,"#43e8ff",0.55); // 雷达扫面
|
||
px(-1,-38,2,2,t%30<15?"#ff3355":"#7a1622");
|
||
ctx.restore();
|
||
// —— 发光纹路(暗纹常存,蓄力时向键带点亮蔓延) ——
|
||
{const pr=(ks&&ks.hotT>0&&ks.hotT0)?1-ks.hotT/ks.hotT0:0;
|
||
for(let k=0;k<5;k++){const tx2=-60+k*30;
|
||
px(tx2,-8,1,12,"#134152");
|
||
if(pr>0){ctx.globalAlpha=pr*0.7;px(tx2,-8,1,12,"#43e8ff");ctx.globalAlpha=1;}}}
|
||
// —— 琴键炮口带(21键像素钢琴:白键+黑键+键缝;键位公式 -(n-1)*5+k*10 与enemies.js同步) ——
|
||
px(-(n-1)*5-5,6,(n-1)*10+10,19,"#0a0e16"); // 键槽
|
||
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(i<n-1&&[0,1,3,4,5].indexOf(i%7)>=0)px(kx+3,8,4,7,"#101318");} // 黑键(钢琴纹样)
|
||
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;}}
|
||
}
|
||
/* ---- 夺权者X:几何装甲板拼装宽体楔形母舰(P1)→ 抛侧舱同风格壮实战机(P2) ----
|
||
参考图核心特征:交错装甲板+深板缝+蓝色发光条纹格栅翼+三联红炮口武器舱+橙/黄小标识;无生物眼(机械反应环) */
|
||
function drawUsurper(b,t,fl,ph2,mp){
|
||
const jt=mp||0;
|
||
// —— P2同风格壮实战机(壳下常存,mp渐显;宽翼板+小武器舱+粗箭形机身) ——
|
||
if(ph2>=1){const di=mp!==null?mp:1;
|
||
ctx.save();ctx.globalAlpha=di;const ds=0.75+0.25*di;ctx.scale(ds,ds);
|
||
for(const sd of[-1,1]){ctx.save();ctx.scale(sd,1); // 后掠翼板(蓝条纹+橙标识+翼根炮口)
|
||
poly([10,-16,34,-24,40,-14,34,-6,12,-6],"#c9d6e2");
|
||
poly([10,-16,34,-24,30,-19,12,-11],"#e8f4ff"); // 翼面受光
|
||
drawSeg(14,-10,30,-19,2,"#43b8ff",0.85); // 蓝色翼纹
|
||
px(30,-22,4,3,"#ff9a3d");px(12,-5,3,3,"#ff3355");
|
||
px(18,4,12,12,"#c9d6e2");px(20,6,8,6,"#2a3444"); // 小武器舱
|
||
px(21,7,3,3,"#ff3355");px(25,7,3,3,"#ff3355"); // 双联红炮口
|
||
px(21,16,3,6,"#5a6c80");px(25,16,3,6,"#5a6c80"); // 舱下炮管
|
||
ctx.restore();}
|
||
poly([0,46,-15,12,-13,-24,-8,-34,8,-34,13,-24,15,12],"#e8f4ff"); // 粗箭形机身
|
||
poly([0,46,15,12,13,-24,8,-34,0,-34],"#9fb0c6");
|
||
px(-1,-22,2,52,t%50<25?"#43b8ff":"#2a5a78"); // 中脊蓝色光带(搏动)
|
||
px(-13,-24,26,2,"#5a6c80");px(-11,-4,22,2,"#5a6c80"); // 装甲板缝
|
||
circ(0,-14,7,"#0d2244"); // 中央反应环(机械环非眼睛)
|
||
ctx.strokeStyle=fl||"#43b8ff";ctx.lineWidth=2;ctx.beginPath();ctx.arc(0,-14,7,0,TAU);ctx.stroke();
|
||
for(let k=0;k<3;k++){const ra=t*0.03+k*TAU/3;ctx.beginPath();ctx.arc(0,-14,7,ra,ra+0.8);ctx.stroke();}
|
||
circ(0,-14,3+Math.sin(t*0.1)*0.5,"#bfefff");
|
||
if(b.laserT>0){ctx.globalAlpha=di*0.5;circ(0,-14,10,"#7ce9ff");ctx.globalAlpha=di;}
|
||
px(-2,2,4,16,"#0d2244");px(-1,4,2,12,t%40<20?"#7fd8ff":"#2a5a78"); // 中线长条蓝窗(参考图特征)
|
||
for(const sd of[-1,1]){px(sd*6-2,-36,4,3,"#5a6c80"); // 双引擎尾焰
|
||
px(sd*6-1.5,-40-(t%4),3,3+(t%4),t%6<3?"#7fd8ff":"#43b8ff");}
|
||
ctx.restore();ctx.globalAlpha=1;}
|
||
// —— P1母舰(变形=翼板/武器舱抛离飞走+舰体淡出) ——
|
||
if(ph2===0||mp!==null){
|
||
// —— 后翼面(格栅翼+蓝条纹×3) ——
|
||
for(const sd of[-1,1]){const ja=(1-jt)*(1-jt*0.9);if(ja<=0.02)continue;
|
||
ctx.save();ctx.translate(sd*jt*110,jt*50);ctx.rotate(sd*jt*0.6);ctx.scale(sd,1);ctx.globalAlpha=ja;
|
||
poly([20,-38,66,-50,76,-40,72,-28,26,-22],"#c9d6e2");
|
||
poly([20,-38,66,-50,60,-44,24,-32],"#e8f4ff"); // 受光面
|
||
for(let k=0;k<3;k++)drawSeg(34+k*12,-34-k*4,44+k*12,-44-k*3,2,"#43b8ff",0.85); // 蓝色翼纹×3
|
||
for(let k=0;k<4;k++)px(30+k*11,-30-k*2,2,8,"#9fb0c6"); // 格栅
|
||
ctx.restore();ctx.globalAlpha=1;}
|
||
// —— 中层装甲翼板×3/侧(交错层叠) ——
|
||
const PL=[[14,-30],[30,-22],[44,-14]];
|
||
for(const sd of[-1,1])for(let L=0;L<3;L++){
|
||
const ja=(1-jt)*(1-jt*0.85);if(ja<=0.02)continue;
|
||
ctx.save();ctx.translate(sd*jt*(80+L*26),jt*(36+L*12));ctx.rotate(sd*jt*(0.45+L*0.2));ctx.scale(sd,1);ctx.globalAlpha=ja;
|
||
const x0=PL[L][0],y0=PL[L][1];
|
||
poly([x0,y0,x0+26,y0+4,x0+22,y0+16,x0+4,y0+14],"#d8e4f0");
|
||
poly([x0+4,y0+14,x0+22,y0+16,x0+26,y0+4,x0+20,y0+8],"#9fb0c6"); // 右下暗边
|
||
poly([x0,y0,x0+26,y0+4,x0+24,y0+6,x0+2,y0+2],"#e8f4ff"); // 上缘受光
|
||
if(L===1)px(x0+16,y0+6,4,3,"#ff9a3d"); // 橙色小标识
|
||
if(L===2)drawSeg(x0+6,y0+3,x0+20,y0+6,2,"#43b8ff",0.8); // 板面蓝纹
|
||
ctx.restore();ctx.globalAlpha=1;}
|
||
// —— 武器舱段(三联红炮口深槽+黄标识+舱下双炮管;deckVolley逐个点亮) ——
|
||
for(const sd of[-1,1]){const ja=(1-jt)*(1-jt*0.85);if(ja<=0.02)continue;
|
||
ctx.save();ctx.translate(sd*jt*95,jt*44);ctx.rotate(sd*jt*0.55);ctx.scale(sd,1);ctx.globalAlpha=ja;
|
||
px(44,0,24,22,"#c9d6e2");px(44,0,24,3,"#e8f4ff");
|
||
px(46,4,20,9,"#2a3444"); // 炮座深槽
|
||
for(let g=0;g<3;g++)px(48+g*6,6,4,5,(b.deckT>0&&(26-b.deckT)>g*6)?"#ffffff":"#ff3355"); // 三联红炮口
|
||
px(45,15,4,3,"#ffcf5c"); // 黄标识
|
||
px(48,22,3,9,"#5a6c80");px(59,22,3,9,"#5a6c80"); // 舱下双炮管
|
||
px(48.5,29,2,3,"#43b8ff");px(59.5,29,2,3,"#43b8ff");
|
||
ctx.restore();ctx.globalAlpha=1;}
|
||
// —— 中央箭形主舰体(最前层:宽顶→尖下巴,中脊光带+反应环+长条蓝窗) ——
|
||
const ha=1-jt;if(ha>0.02){ctx.save();ctx.globalAlpha=ha;
|
||
poly([0,54,-17,10,-15,-26,-9,-40,9,-40,15,-26,17,10],"#e8f4ff");
|
||
poly([0,54,17,10,15,-26,9,-40,0,-40],"#9fb0c6"); // 右半暗面
|
||
px(-1,-28,2,66,t%50<25?"#43b8ff":"#2a5a78"); // 中脊蓝色光带(搏动)
|
||
px(-15,-26,30,2,"#5a6c80");px(-13,-2,26,2,"#5a6c80"); // 板缝
|
||
for(let k=0;k<4;k++)px(-12+k*7,-25,2,2,"#8a9ab8"); // 铆钉
|
||
circ(0,-18,8,"#0d2244"); // 中央反应环(机械环非眼睛)
|
||
ctx.strokeStyle=fl||"#43b8ff";ctx.lineWidth=2;ctx.beginPath();ctx.arc(0,-18,8,0,TAU);ctx.stroke();
|
||
for(let k=0;k<3;k++){const ra=t*0.02+k*TAU/3;ctx.beginPath();ctx.arc(0,-18,8,ra,ra+0.7);ctx.stroke();}
|
||
circ(0,-18,3.5+Math.sin(t*0.08)*0.5,"#bfefff");
|
||
if(b.laserT>0){ctx.globalAlpha=ha*0.5;circ(0,-18,11,"#7ce9ff");ctx.globalAlpha=ha;}
|
||
px(-2.5,4,5,22,"#0d2244");px(-1,6,2,18,t%40<20?"#7fd8ff":"#2a5a78"); // 中线长条蓝窗(参考图特征)
|
||
for(let e=0;e<3;e++){const ex2=-10+e*10; // 顶部引擎列
|
||
px(ex2-2,-42,4,3,"#5a6c80");
|
||
px(ex2-1.5,-46-(t+e*2)%4,3,3+(t+e*2)%4,e%2?"#7fd8ff":"#43b8ff");}
|
||
ctx.restore();ctx.globalAlpha=1;}
|
||
}
|
||
}
|
||
/* ---- 暗黑魔碟:8扇区缝合装甲碟+红能量窗/裂纹+紫红竖瞳魔眼 ----
|
||
变形沿用原机制(mp优先):P2圆环绕顶轴外旋裂开+魔眼点亮;P3爆甲壳板飞离+铆钉伸长成刺+犄角炮台 */
|
||
function drawSaucer(b,t,fl,ph2,mp){
|
||
let open,fo,eyeG;
|
||
if(ph2===0){open=0;fo=0;eyeG=0;}
|
||
else if(ph2===1){open=mp!==null?mp:1;fo=0;eyeG=mp!==null?mp:1;}
|
||
else{open=1;fo=mp!==null?mp:1;eyeG=1;}
|
||
const R=30+open*3;
|
||
// —— 碟心基盘+8装甲扇区(扇区纹饰缓转,眼不转=诡异感;扇区间红裂纹随阶段增亮) ——
|
||
circ(0,0,20,"#1a1030");circ(0,0,15,"#12081c");
|
||
ctx.save();ctx.rotate(t*0.004);
|
||
for(let k=0;k<8;k++){ctx.save();ctx.rotate(k*TAU/8);
|
||
poly([0,-19,6,-14,4,-8,-4,-8,-6,-14],k%2?"#241430":"#2a1a3a"); // 扇区装甲(明暗交替)
|
||
px(-0.5,-19,1,11,open>0?"#ff3355":"#7a1622"); // 扇区间裂纹(P2转亮红)
|
||
ctx.restore();}
|
||
for(let k=0;k<8;k++){const a=(k+0.5)*TAU/8; // 红色六边形能量窗(随扇区角度旋转,呼吸明灭)
|
||
ctx.globalAlpha=(0.3+0.3*Math.sin(t*0.08+k*1.1))*(0.5+0.5*eyeG);
|
||
ctx.save();ctx.translate(Math.sin(a)*12.5,-Math.cos(a)*12.5);ctx.rotate(a);
|
||
px(-2,-1,4,2,"#ff3355");px(-1,-2,2,4,"#ff3355");
|
||
ctx.restore();ctx.globalAlpha=1;}
|
||
ctx.restore();
|
||
// —— 眼窝(常存)+紫红魔眼(P2点亮;竖瞳追踪玩家,P3瞳孔收成竖缝) ——
|
||
px(-11,-5,7,6,"#241430");px(4,-5,7,6,"#241430");
|
||
if(eyeG>0){ctx.globalAlpha=eyeG;
|
||
px(-10,-4,5,4,"#c86bff");px(5,-4,5,4,"#c86bff");
|
||
const pu=clamp((G.p.x-b.x)*0.02,-1.5,1.5);
|
||
px(-8.5+pu,-4,ph2>=2?1:1.8,4,fl||"#ff3355");px(6.5+pu,-4,ph2>=2?1:1.8,4,fl||"#ff3355");
|
||
ctx.globalAlpha=1;}
|
||
// —— 外环:12节分节环(节间红发光条呼吸);变形=绕顶轴外旋裂开、下端伸长变犄角(同一几何体连续演化) ——
|
||
const rot=open*0.55;
|
||
for(const sd of[-1,1]){ctx.save();
|
||
ctx.translate(0,-R);ctx.rotate(-sd*rot);ctx.translate(0,R);
|
||
const a0=sd<0?Math.PI/2:-Math.PI/2,a1=sd<0?Math.PI*1.5:Math.PI/2;
|
||
for(let sg=0;sg<6;sg++){const sa0=a0+sg*(a1-a0)/6+0.04,sa1=a0+(sg+1)*(a1-a0)/6-0.04; // 6节/半环
|
||
ctx.strokeStyle="#2a1a3a";ctx.lineWidth=11;
|
||
ctx.beginPath();ctx.arc(0,0,R,sa0,sa1);ctx.stroke();
|
||
ctx.strokeStyle="#55336e";ctx.lineWidth=4.5;
|
||
ctx.beginPath();ctx.arc(0,0,R,sa0,sa1);ctx.stroke();}
|
||
for(let k=0;k<5;k++){const ag=a0+(k+1)*(a1-a0)/6; // 节间红发光条(径向对齐,呼吸明灭)
|
||
ctx.globalAlpha=0.45+0.4*Math.sin(t*0.09+k);
|
||
ctx.save();ctx.translate(Math.cos(ag)*R,Math.sin(ag)*R);ctx.rotate(ag);
|
||
px(-4,-1,8,2,"#ff3355");ctx.restore();ctx.globalAlpha=1;}
|
||
const hL=3+open*26; // 半环下端伸长变尖:圆环下半部分延续为朝下的锥刺(同一几何体)
|
||
poly([-6.5,R,6.5,R,2.5,R+hL*0.55,0,R+hL,-2.5,R+hL*0.55],"#2a1a3a");
|
||
poly([-3.5,R,3.5,R,1.2,R+hL*0.5,0,R+hL*0.8,-1.2,R+hL*0.5],"#55336e");
|
||
for(let k=0;k<3;k++){const aa=a0+(sd<0?0.35+k*0.2:0.65-k*0.2)*(a1-a0); // 左右半环镜像对称
|
||
const rx=Math.cos(aa),ry=Math.sin(aa),tx2=-ry,ty2=rx;
|
||
const bl=2+9*fo; // 铆钉→尖刺连续伸长
|
||
poly([rx*(R+5)+tx2*2.5,ry*(R+5)+ty2*2.5, rx*(R+5)-tx2*2.5,ry*(R+5)-ty2*2.5, rx*(R+5+bl),ry*(R+5+bl)],fo>0.6?(fl||"#ff3355"):"#241430");
|
||
if(fo<0.99){ctx.save(); // 外壳板:爆甲时旋转飞离(有运动轨迹,非消失)
|
||
ctx.translate(rx*(R+9+fo*22)+tx2*fo*sd*9,ry*(R+9+fo*22)+ty2*fo*sd*9);
|
||
ctx.rotate(aa+Math.PI/2+fo*sd*1.7);ctx.globalAlpha=1-fo;
|
||
px(-5,-3,10,6,"#2a1a3a");px(-5,-3,10,2,"#55336e");
|
||
ctx.restore();ctx.globalAlpha=1;}}
|
||
{const ta=a0+0.5*(a1-a0),bl2=2+6*fo; // 红色犄角炮台:基座常存,爆甲后炮管伸出点亮
|
||
ctx.save();ctx.translate(Math.cos(ta)*(R+2),Math.sin(ta)*(R+2));ctx.rotate(ta+Math.PI/2);
|
||
px(-2.5,-3,5,4,"#241430");
|
||
px(-1.5,-3-bl2,3,bl2,fo>0.4?(fl||"#ff3355"):"#3a2248");
|
||
ctx.restore();}
|
||
ctx.restore();}
|
||
circ(0,-R,4,"#55336e"); // 顶部铰链节
|
||
}
|
||
/* ---- 太空原种/暗黑突击绘制(从render.js迁入,集中管理Boss美术) ---- */
|
||
function drawProgenitor(b,t,fl,tf){ // 太空原种·装甲虫兽(tf 0=装甲态→1=血肉态):P1小翅芽→P2骨膜巨翼;无复眼(大颚+感器红缝=虫形压迫感);摆尾衔接于躯体之下(尾根被加长的身体覆住,无缝)
|
||
ctx.rotate(Math.sin(t*0.05)*0.04); // 悬停微摇
|
||
const wS=0.22+0.78*tf; // 翼展:P1小翅芽→P2全展(同一对翼连续缩放)
|
||
// —— 骨膜翼一对:3根骨刺撑起膜面(P1灰甲小翼→P2血红膜+暗红骨,同一几何体罩色) ——
|
||
for(const sd of[-1,1]){ctx.save();
|
||
const flut=b.rainT>0?Math.sin(t*0.62)*0.13:Math.sin(t*0.07)*0.03; // 红雨前摇/洒落期双翼高频抖动
|
||
ctx.translate(sd*7,-8);ctx.scale(sd*wS,1+flut); // 呼吸/抖动+镜像
|
||
poly([0,-4,14,-16,34,-16,54,-10,48,0,34,6,16,4,0,2],"#c9d6e2"); // 膜面主甲
|
||
poly([0,-4,14,-16,34,-16,54,-10,40,-8,18,-8,0,-1],"#e8f0f6"); // 上缘受光
|
||
poly([0,2,16,4,34,6,48,0,36,0,14,2],"#8498ac"); // 下缘暗面
|
||
for(const tp of[[14,-15],[34,-15],[54,-9]])drawSeg(2,-2,tp[0],tp[1],2,"#8498ac",1); // 3根骨刺(辐射)
|
||
if(tf>0){ctx.globalAlpha=tf*0.85;
|
||
poly([0,-4,14,-16,34,-16,54,-10,48,0,34,6,16,4,0,2],"#c02030"); // P2膜面转血红(同面罩色)
|
||
for(const tp of[[14,-15],[34,-15],[54,-9]])drawSeg(2,-2,tp[0],tp[1],2,"#7a1622",tf); // P2骨刺转暗红
|
||
ctx.globalAlpha=1;}
|
||
ctx.restore();}
|
||
// —— 摆尾:先画在躯体下层(尾根被加长的身体覆住,无缝衔接),5节逐节相位摆动;P2节间血红肉显露+整体伸长 ——
|
||
const segH=5.2+tf*1.6,gap=11;
|
||
for(let i=4;i>=0;i--){const sw=Math.sin(t*0.055+i*0.7)*(0.8+i),sy=gap+i*segH,hw=9-i*1.5;
|
||
if(tf>0&&i<4){ctx.globalAlpha=tf*0.85;px(sw-hw+2,sy+segH-2,(hw-2)*2,2,"#c8202e");ctx.globalAlpha=1;} // 节间血肉环
|
||
poly([sw-hw,sy,sw+hw,sy,sw+hw-2,sy+segH,sw-hw+2,sy+segH],i%2?"#b8c8d8":"#c9d6e2"); // 尾节甲片
|
||
px(sw-hw,sy,3,segH,"#e8f0f6");px(sw+hw-3,sy,3,segH,"#8498ac"); // 左亮右暗
|
||
for(const sd of[-1,1])poly([sw+sd*(hw+1),sy+1,sw+sd*(hw+4),sy+2.5,sw+sd*(hw+1),sy+4],"#e8dcc0"); // 节侧骨刺
|
||
}
|
||
const swT=Math.sin(t*0.055+2.8)*4.8,tipY=gap+4*segH; // 尾末生殖腔(花弹发射口,与enemies.js同源公式)
|
||
circ(swT,tipY+2,2.6+Math.sin(t*0.11)*0.6,fl||(tf>0.5?"#ff2a3c":"#ff5566"));
|
||
circ(swT,tipY+2,1.1,"#ffdfe5");
|
||
// —— 壳下血肉(常存于背甲之下,滑开才见;血红,非粉) ——
|
||
if(tf>0){ctx.globalAlpha=tf*0.9;
|
||
poly([0,-36,9,-29,11,-14,10,2,9,14,7,16,-7,16,-9,14,-10,2,-11,-14,-9,-29],"#c8202e");
|
||
px(-2,-30,4,45,"#e8393a");ctx.globalAlpha=1;}
|
||
// —— 背甲两瓣:绕尾端枢轴楔开(顶端外摆露血肉、尾端原地不动,衔接处不变宽;同一几何体旋转) ——
|
||
for(const sd of[-1,1]){ctx.save();ctx.translate(0,14);ctx.rotate(sd*tf*0.28);ctx.translate(0,-14);
|
||
poly([0,-40,sd*11,-37,sd*15,-28,sd*13,-12,sd*12,4,sd*11,14,0,14],sd<0?"#c9d6e2":"#9fb0c2"); // 末端平边与尾节同材质(#c9d6e2)
|
||
px(sd<0?-11:0,12,11,2,sd<0?"#e8f0f6":"#8498ac"); // 底缘左亮右暗(与尾节描边一致,接缝读作甲片缝)
|
||
poly([0,-40,sd*11,-37,sd*15,-28,sd*7,-26,sd*5,-36],"#e8f0f6"); // 受光斜面
|
||
for(let i=0;i<4;i++)px(sd*(4+i*2.8)-1,-24+i*9,2,5,"#5a6c80"); // 甲片板缝
|
||
const crk=Math.max(0,Math.min(1,(tf-0.15)/0.4))*10; // 裂纹随tf生长(延长,非新增)
|
||
if(crk>0.5)px(sd*6-1,-18,2,crk,"#8a2a3a");
|
||
ctx.restore();}
|
||
// —— 头部:圆顶甲+锯齿犄角+下弯大颚(无复眼=虫形压迫感)+一线感器红缝 ——
|
||
circ(0,-34,10,"#dde7f0");px(-9,-36,18,3,"#9fb0c2");
|
||
for(const sd of[-1,1]){poly([sd*6,-40,sd*15,-49,sd*12,-51,sd*4,-43],"#8498ac");
|
||
poly([sd*10,-44,sd*13,-48,sd*11,-43],"#5a6c80"); // 犄角锯齿棱
|
||
px(sd*9-1,-46,2,4,"#7dff8a");} // 犄角绿纹
|
||
px(-5,-33,10,1.6,t%30<15?"#ff3355":"#7a1622"); // 感器红缝(明灭)
|
||
for(const sd of[-1,1]){poly([sd*3,-26,sd*9,-22,sd*8,-14,sd*5,-13,sd*2,-20],"#e8dcc0"); // 下弯大颚(骨白)
|
||
px(sd*5,-16,2,3,"#8a6a4a");} // 颚尖暗色
|
||
if(b.eyeGlow>0){ctx.globalAlpha=b.eyeGlow/20; // 击发余辉:大颚+感器缝闪白
|
||
px(-8,-22,4,3,"#fff");px(4,-22,4,3,"#fff");px(-5,-33,10,1.6,"#fff");ctx.globalAlpha=1;}
|
||
// —— 头侧青色管囊(P2转荧绿) ——
|
||
for(const sd of[-1,1]){px(sd*15-2.5,-18,5,12,tf>0.5?"#7dff8a":(t%40<20?"#7fd8ff":"#43b8ff"));
|
||
px(sd*15-1.5,-20,3,3,"#55648a");}
|
||
}
|
||
function drawAssault(t,fl,swp,ph,mp){ // 暗黑突击(swp=翼展角;炮管/推进器随阶段增多)
|
||
const sw=swp*Math.PI/180;
|
||
for(const sd of[-1,1]){
|
||
const tx=sd*(8+52*Math.sin(sw)),ty=14-52*Math.cos(sw);
|
||
poly([sd*4,6,tx,ty,tx-sd*9,ty+11,sd*4,20],ph>=2?"#c01a2e":"#a01224");
|
||
poly([tx-sd*2,ty-6,tx+sd*3,ty-14,tx+sd*7,ty-3],"#6e0c1a");}
|
||
poly([0,38,-5,6,-3,-26,3,-26,5,6],"#d4233a");
|
||
px(-2,8,4,8,fl||"#ffd23d");
|
||
const guns=[[16,4],[-16,4],[30,-4],[-30,-4],[42,-10],[-42,-10]];
|
||
const gn=ph>=2?6:ph>=1?4:2,pgn=ph===2?4:ph===1?2:0;
|
||
for(let i=0;i<gn;i++){let gl=8;if(mp!==null&&i>=pgn)gl=Math.max(1,8*mp); // 新炮管生长
|
||
px(guns[i][0]-1.5,guns[i][1],3,gl,"#3a0a10");px(guns[i][0]-1,guns[i][1]+gl-2,2,2,"#ff9a3d");}
|
||
const eng=[[7,-26],[-7,-26],[0,-30],[14,-22]];
|
||
const en=ph>=2?4:ph>=1?3:2,pen=ph===2?3:ph===1?2:0;
|
||
for(let i=0;i<en;i++){let el=5+(t%4<2?2:0);if(mp!==null&&i>=pen)el=Math.max(1,el*mp); // 新推进器
|
||
px(eng[i][0]-2,eng[i][1],4,3,"#5a0a14");
|
||
px(eng[i][0]-1.5,eng[i][1]-3-el,3,el,t%6<3?"#ff9a3d":"#ffcf5c");}
|
||
if(ph>=1){poly([-52,-14,-24,-3,-22,-1,-50,-11],"#ffdfe5");poly([52,-14,24,-3,22,-1,50,-11],"#ffdfe5");}
|
||
if(ph>=2){px(-4,-16,8,12,fl||"#ff3355");px(-2,-14,4,8,"#ffdfe5");}
|
||
}
|
||
function drawAssaultGhost(swp,ph){ // 暗黑突击冲撞红色残影:与机体同轮廓同线条(纯红系,供dashTrail叠画)
|
||
const sw=swp*Math.PI/180;
|
||
for(const sd of[-1,1]){
|
||
const tx=sd*(8+52*Math.sin(sw)),ty=14-52*Math.cos(sw);
|
||
poly([sd*4,6,tx,ty,tx-sd*9,ty+11,sd*4,20],"#ff3344"); // 主翼
|
||
poly([tx-sd*2,ty-6,tx+sd*3,ty-14,tx+sd*7,ty-3],"#ff3344");} // 翼尖
|
||
poly([0,38,-5,6,-3,-26,3,-26,5,6],"#ff3344"); // 机身
|
||
px(-2,8,4,8,"#ff8899"); // 中脊亮线
|
||
const guns=[[16,4],[-16,4],[30,-4],[-30,-4],[42,-10],[-42,-10]];
|
||
const gn=ph>=2?6:ph>=1?4:2;
|
||
for(let i=0;i<gn;i++)px(guns[i][0]-1.5,guns[i][1],3,8,"#ff8899"); // 炮管
|
||
const eng=[[7,-26],[-7,-26],[0,-30],[14,-22]];
|
||
const en=ph>=2?4:ph>=1?3:2;
|
||
for(let i=0;i<en;i++)px(eng[i][0]-1.5,eng[i][1]-10,3,7,"#ff8899"); // 推进器
|
||
if(ph>=1){poly([-52,-14,-24,-3,-22,-1,-50,-11],"#ff3344");poly([52,-14,24,-3,22,-1,50,-11],"#ff3344");} // 翼展线条
|
||
if(ph>=2)px(-4,-16,8,12,"#ff8899"); // 中核亮块
|
||
}
|
||
/* ---- Boss光束与浮游炮渲染 ---- */
|