From 10e5744da7b92b7051050ce47995de676842254e Mon Sep 17 00:00:00 2001 From: JOJO <1498581755@qq.com> Date: Thu, 6 Aug 2026 03:31:34 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9A=97=E9=BB=91=E9=AD=94=E7=A2=9F=E9=87=8D?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1=EF=BC=9A=E7=BE=8E=E6=9C=AF=E5=A4=A7=E6=94=B9?= =?UTF-8?q?=3D8=E6=89=87=E5=8C=BA=E7=BC=9D=E5=90=88=E8=A3=85=E7=94=B2?= =?UTF-8?q?=E7=A2=9F=EF=BC=88=E6=89=87=E5=8C=BA=E7=BA=B9=E9=A5=B0=E7=BC=93?= =?UTF-8?q?=E8=BD=AC=E7=9C=BC=E4=B8=8D=E8=BD=AC=EF=BC=89+=E7=BA=A2?= =?UTF-8?q?=E8=89=B2=E5=85=AD=E8=BE=B9=E5=BD=A2=E8=83=BD=E9=87=8F=E7=AA=97?= =?UTF-8?q?=E5=91=BC=E5=90=B8+=E6=89=87=E5=8C=BA=E7=BA=A2=E8=A3=82?= =?UTF-8?q?=E7=BA=B9+12=E8=8A=82=E5=88=86=E8=8A=82=E7=8E=AF=E7=BA=A2?= =?UTF-8?q?=E5=8F=91=E5=85=89=E6=9D=A1+=E7=B4=AB=E7=BA=A2=E7=AB=96?= =?UTF-8?q?=E7=9E=B3=E9=AD=94=E7=9C=BC=EF=BC=88=E8=BF=BD=E8=B8=AA=E7=8E=A9?= =?UTF-8?q?=E5=AE=B6=EF=BC=8CP3=E6=94=B6=E7=AB=96=E7=BC=9D=EF=BC=89?= =?UTF-8?q?=EF=BC=9B=E5=8F=98=E5=BD=A2=E6=B2=BF=E7=94=A8=E7=8E=AF=E8=A3=82?= =?UTF-8?q?=E6=88=90=E7=8A=84=E8=A7=92+=E7=88=86=E7=94=B2=E6=9C=BA?= =?UTF-8?q?=E5=88=B6=EF=BC=9B=E6=94=BB=E5=87=BB=E5=B0=8F=E6=94=B9=3D?= =?UTF-8?q?=E7=AD=BE=E5=90=8D=E5=BC=B9=E7=8E=AFP2=E8=B5=B7=E5=8A=A0?= =?UTF-8?q?=E5=86=85=E5=B1=82=E5=8F=8D=E5=90=91=E6=A9=99=E5=BC=B9=EF=BC=88?= =?UTF-8?q?=E5=8F=8C=E5=B1=82=E7=BC=96=E7=BB=87=E7=B4=AB+=E6=A9=99?= =?UTF-8?q?=EF=BC=89/ringBig=E6=94=B9=E6=A9=99=E5=BC=B9=E3=80=82=E5=8F=A6?= =?UTF-8?q?=EF=BC=9AdrawProgenitor/drawAssault=E8=BF=81=E5=85=A5boss=5Fart?= =?UTF-8?q?.js=EF=BC=88render.js=E9=99=8D=E8=87=B3477=E8=A1=8C=EF=BC=89?= =?UTF-8?q?=EF=BC=8CAGENTS.md=E5=90=8C=E6=AD=A5=E3=80=82=E4=BB=85=E8=AF=AD?= =?UTF-8?q?=E6=B3=95=E6=A3=80=E6=9F=A5=E9=80=9A=E8=BF=87=EF=BC=8C=E6=9C=AA?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 3 +- star-raid/js/boss_art.js | 135 +++++++++++++++++++++++++++++++++++++++ star-raid/js/enemies.js | 5 +- star-raid/js/render.js | 118 +--------------------------------- 4 files changed, 143 insertions(+), 118 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f1eef04..1ccb2b3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,7 +42,8 @@ star-raid/ │ ├── core.js # 游戏状态 G、发射逻辑、explodeFx 爆炸特效库 │ ├── combat.js # 子弹运动/碰撞/光束判定/zones 区域效果 │ ├── enemies.js # ENEMIES 杂兵表、BOSSES 表、bossMain/bossMinor 攻击库 -│ ├── render.js # 全部渲染(drawBoss 各 Boss 绘制、zones、子弹) +│ ├── render.js # 世界渲染(drawBoss 分支调度、血条、子弹、zones) +│ ├── boss_art.js # Boss 美术库(drawProgenitor/drawAssault/drawPiano/drawUsurper/drawSaucer) │ ├── sprites.js # 像素字符画 bake 系统、SPR 精灵表、BHALO 弹光晕 │ ├── audio.js # SFX 音效(WebAudio 合成) │ └── ui.js # 菜单/图鉴/rush 选择/老虎机/结算 diff --git a/star-raid/js/boss_art.js b/star-raid/js/boss_art.js index c74353f..cec10e5 100644 --- a/star-raid/js/boss_art.js +++ b/star-raid/js/boss_art.js @@ -128,3 +128,138 @@ function drawUsurper(b,t,fl,ph2,mp){ 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; // 红色六边形能量窗(呼吸明灭,P2+更亮) + ctx.globalAlpha=(0.3+0.3*Math.sin(t*0.08+k*1.1))*(0.5+0.5*eyeG); + circ(Math.sin(a)*12.5,-Math.cos(a)*12.5,2.2,"#ff3355");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); + px(Math.cos(ag)*R-1,Math.sin(ag)*R-4,2,8,"#ff3355");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+(0.35+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=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=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");} +} +/* ---- Boss光束与浮游炮渲染 ---- */ diff --git a/star-raid/js/enemies.js b/star-raid/js/enemies.js index 0da68dd..1a0c13b 100644 --- a/star-raid/js/enemies.js +++ b/star-raid/js/enemies.js @@ -446,6 +446,9 @@ function bossMain(b,def,fm){ const n2=12+ph*5; for(let i=0;i=1){const n3=6+ph*3; // P2起内层反向橙弹环(双层反向编织,致敬参考图紫+橙) + for(let i=0;i=2?24:ph===1?30:36)/fm); if(ph>=1&&(!b.eyeT||b.eyeT<=0)){const ex=ap2.x; @@ -485,7 +488,7 @@ function bossMinor(b,mk,fm){ case "deckVolley": if(b.phase>=1){b.minorT=80;break;}b.deckT=26;b.minorT=Math.round(320/fm);break; // 夺权者X:甲板齐射(P1限定)——最下甲板炮口逐个点亮前摇→6发垂直弹雨 case "pillar": {const px2=rnd(40,W-40);bossBeam(px2,-6,px2,H+8,4,"#b98cff",26,26,18);b.minorT=Math.round(220/fm);break;} case "eyeBeam": bossBeam(b.x,b.y+6,ap2.x,H+8,4,"#ff3355",22,24,20);b.minorT=Math.round(180/fm);break; - case "ringBig": for(let i=0;i<18;i++)ebul(b.x,b.y,i/18*TAU-b.t*0.03,1.8,"orbP",15);b.minorT=Math.round(230/fm);break; + case "ringBig": for(let i=0;i<18;i++)ebul(b.x,b.y,i/18*TAU-b.t*0.03,1.8,"orbO",15);b.minorT=Math.round(230/fm);break; // 橙环(与签名紫锥拉开) case "sporeArc": for(let i=0;i<7;i++)ebul(b.x,b.y+14,Math.PI/2+(i-3)*0.26,1.2,"orbG",13);b.minorT=Math.round(210/fm);break; // 原种:慢速孢子幕(绿,与花弹差异化) case "tentBeam": { // 原种:双触手鞭击光束——从头侧管囊伸出,锚定相位从垂直向下逐帧向外鞭展(sweep连续判定,扫到哪判定到哪) const ph0=-G.time*0.014; diff --git a/star-raid/js/render.js b/star-raid/js/render.js index 36448a2..c283cc0 100644 --- a/star-raid/js/render.js +++ b/star-raid/js/render.js @@ -171,47 +171,8 @@ function drawBoss(){ for(let i=0;i<8;i++){const a=i*TAU/8+t*0.02,tx3=Math.cos(a)*mw*0.82,ty3=Math.sin(a)*mw*0.82; poly([tx3-1.5,30+ty3,tx3+1.5,30+ty3,tx3*0.6,30+ty3*0.6],"#e8dcc0");}} ctx.restore(); - }else{ // 暗黑魔碟:核心+圆环;变形=圆环前后裂开、两半各自收缩成犄角(同一几何体连续演化);爆甲=壳板飞离、铆钉伸长成刺 - let open,fo,eyeG; - if(b.phase===0){open=0;fo=0;eyeG=0;} - else if(b.phase===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; // 外径微扩 - circ(0,0,20,"#1a1030");circ(0,0,15,"#12081c"); - px(-11,-5,7,6,"#241430");px(4,-5,7,6,"#241430"); // 眼窝常存 - if(eyeG>0){ctx.globalAlpha=eyeG; // 赤瞳点亮(非凭空出现) - px(-10,-4,5,4,fl||"#ff3355");px(5,-4,5,4,fl||"#ff3355"); - px(-9,-3,2,1,"#ffdfe5");px(6,-3,2,1,"#ffdfe5"); - ctx.globalAlpha=1;} - 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; // 左半环/右半环 - ctx.strokeStyle="#55336e";ctx.lineWidth=13; - ctx.beginPath();ctx.arc(0,0,R,a0,a1);ctx.stroke(); - ctx.strokeStyle="#6e4490";ctx.lineWidth=5; - ctx.beginPath();ctx.arc(0,0,R,a0,a1);ctx.stroke(); - 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],"#55336e"); - poly([-3.5,R,3.5,R,1.2,R+hL*0.5,0,R+hL*0.8,-1.2,R+hL*0.5],"#6e4490"); - for(let k=0;k<3;k++){const aa=a0+(0.35+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?"#c86bff":"#2a1a3a"); - 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,"#55336e");px(-5,-3,10,2,"#6e4490"); - 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,"#2a1a3a"); - px(-1.5,-3-bl2,3,bl2,fo>0.4?(fl||"#ff3355"):"#3a2248"); - ctx.restore();} - for(let k=0;k<2;k++){const aa2=a0+(0.35+k*0.3)*(a1-a0)+Math.sin(t*0.012+k*2)*0.05; // 环面光点 - px(Math.cos(aa2)*R-2,Math.sin(aa2)*R-2,4,4,"#c86bff");} - ctx.restore();} - circ(0,-R,4,"#6e4490"); // 顶部铰链节 + }else{ // 暗黑魔碟:8扇区缝合装甲碟+红能量窗裂纹+紫红竖瞳魔眼(变形沿用,mp优先) + drawSaucer(b,t,fl,ph2,mp); } if(flashA>0){ctx.globalAlpha=flashA;ctx.strokeStyle="#fff"; ctx.beginPath();ctx.arc(0,0,b.r+6,0,TAU);ctx.stroke();ctx.globalAlpha=1;} @@ -238,81 +199,6 @@ function drawBoss(){ ctx.fillText(b.transT>0?b.name:(b.name+" "+Math.ceil(pc*100)+"%"),W/2,22); } /* ---- 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=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=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");} -} -/* ---- Boss光束与浮游炮渲染 ---- */ function drawFunnel(f){ // 蓝白长钉无人机(单架,带光环) ctx.strokeStyle="rgba(127,216,255,0.7)";ctx.lineWidth=1; ctx.beginPath();ctx.ellipse(f.x,f.y-1,6,2.5,0,0,TAU);ctx.stroke(); // 光环