原种/魔碟变形重写:同一几何体连续演化,杜绝部件凭空出现

- 太空原种:蛹体保持同一多边形,翅膀折叠藏于身后逐渐展开,裂纹逐条生长,眼青->红、侧囊青->绿渐变(删除drawPupa/drawManta双套形体切换)
- 暗黑魔碟:圆环=左右两个半环,变形为两半环裂口扩张各自收缩成犄角;眼窝常存赤瞳点亮;三阶段爆甲=壳板带轨迹旋飞飞离+铆钉连续伸长成刺+炮台基座伸出炮管
This commit is contained in:
JOJO 2026-08-05 20:45:37 +08:00
parent 5d4ce6b969
commit 45017fbd3f

View File

@ -56,9 +56,8 @@ function drawBoss(){
for(let i=-2;i<=2;i++)px(i*8-1,12,2,3,t%40<20?"#ff5566":"#7a1622"); for(let i=-2;i<=2;i++)px(i*8-1,12,2,3,t%40<20?"#ff5566":"#7a1622");
px(-22,-10,44,2,"#8c9ab8"); px(-22,-10,44,2,"#8c9ab8");
if(ph2>=1){px(-2,-27,4,8,"#5b6b8c");px(-1,-29,2,3,t%20<10?"#ff5566":"#7a1622");} // 二阶段顶部炮塔 if(ph2>=1){px(-2,-27,4,8,"#5b6b8c");px(-1,-29,2,3,t%20<10?"#ff5566":"#7a1622");} // 二阶段顶部炮塔
}else if(b.idx===1){ // 太空原种:虫蛹↔蝠鲼(变身:裂皮→变粉→红眼→展翅) }else if(b.idx===1){ // 太空原种:同一躯体连续变形——裂皮→粉化→红眼→身后展翅(无部件凭空出现)
if(mp!==null){if(mp<0.5)drawPupa(t,fl,mp*2);else drawManta(t,fl,(mp-0.5)*2);} drawProgenitor(t,fl,mp!==null?mp:(ph2===0?0:1));
else if(ph2===0)drawPupa(t,fl,0);else drawManta(t,fl,1);
}else if(b.idx===2){ // 歼灭者 }else if(b.idx===2){ // 歼灭者
for(let i=0;i<6;i++){const a=i/6*TAU+t*0.01; for(let i=0;i<6;i++){const a=i/6*TAU+t*0.01;
px(Math.cos(a)*19-3,Math.sin(a)*19-3,6,6,"#5b3a8c");} px(Math.cos(a)*19-3,Math.sin(a)*19-3,6,6,"#5b3a8c");}
@ -110,36 +109,44 @@ function drawBoss(){
circ(0,-14,8,fl||"#43b8ff");circ(0,-14,4,"#bfefff"); circ(0,-14,8,fl||"#43b8ff");circ(0,-14,4,"#bfefff");
px(-2,-36,4,18,"#43b8ff");px(-2,0,4,34,"#43b8ff"); px(-2,-36,4,18,"#43b8ff");px(-2,0,4,34,"#43b8ff");
ctx.restore();ctx.globalAlpha=1;} ctx.restore();ctx.globalAlpha=1;}
}else{ // 暗黑魔碟:核心+圆环;二阶段圆环前段裂成犄角+赤瞳激光;三阶段爆甲出刺+炮台 }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"); circ(0,0,20,"#1a1030");circ(0,0,15,"#12081c");
if(ph2===0&&mp===null){ // 一阶段:完整圆环绕核心缓转 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 sB=Math.PI/2-open*0.55,sT=Math.PI/2-open*0.35; // 半环跨幅:前端裂口扩得更快
for(const sd of[-1,1]){
const a0=sd<0?Math.PI-sB:-sT,a1=sd<0?Math.PI+sT:sB; // 左半环[π-sB,π+sT] 右半环[-sT,sB]
ctx.strokeStyle="#55336e";ctx.lineWidth=13; ctx.strokeStyle="#55336e";ctx.lineWidth=13;
ctx.beginPath();ctx.arc(0,0,30,0,TAU);ctx.stroke(); ctx.beginPath();ctx.arc(0,0,R,a0,a1);ctx.stroke();
ctx.strokeStyle="#6e4490";ctx.lineWidth=5; ctx.strokeStyle="#6e4490";ctx.lineWidth=5;
ctx.beginPath();ctx.arc(0,0,30,0,TAU);ctx.stroke(); ctx.beginPath();ctx.arc(0,0,R,a0,a1);ctx.stroke();
for(let i=0;i<4;i++){const a=i*Math.PI/2+t*0.012; for(const ea of[a0,a1]){ctx.save(); // 裂口断茬(随弧端移动)
px(Math.cos(a)*30-2,Math.sin(a)*30-2,4,4,"#c86bff");} ctx.translate(Math.cos(ea)*R,Math.sin(ea)*R);ctx.rotate(ea+Math.PI/2);
px(-6,-4,12,8,"#2a1a3a"); px(-6,-8,12,4,"#2a1a3a");px(-3,-11,6,3,"#2a1a3a");ctx.restore();}
}else{ for(let k=0;k<3;k++){const aa=a0+(0.32+k*0.18)*(a1-a0);
if(mp!==null&&b.phase===1){ // 变形中:圆环残留快速淡出 const rx=Math.cos(aa),ry=Math.sin(aa),tx2=-ry,ty2=rx;
const ra=1-clamp(mp/0.35,0,1); const bl=2+9*fo; // 铆钉→尖刺连续伸长
if(ra>0){ctx.globalAlpha=ra;ctx.strokeStyle="#55336e";ctx.lineWidth=13; 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");
ctx.beginPath();ctx.arc(0,0,30,0,TAU);ctx.stroke();ctx.globalAlpha=1;}} if(fo<0.99){ctx.save(); // 外壳板:爆甲时旋转飞离(有运动轨迹,非消失)
const ha=mp!==null?clamp((mp-0.25)/0.6,0,1):1; // 犄角展开度 ctx.translate(rx*(R+9+fo*22)+tx2*fo*sd*9,ry*(R+9+fo*22)+ty2*fo*sd*9);
if(ha>0){ctx.globalAlpha=ha; ctx.rotate(aa+Math.PI/2+fo*sd*1.7);ctx.globalAlpha=1-fo;
for(const sd of[-1,1]){ctx.save();ctx.rotate((1-ha)*sd*1.1); px(-5,-3,10,6,"#55336e");px(-5,-3,10,2,"#6e4490");
poly([sd*10,4,sd*30,-26,sd*46,-32,sd*40,-6,sd*20,12],"#55336e"); ctx.restore();ctx.globalAlpha=1;}}
poly([sd*16,2,sd*32,-20,sd*40,-24,sd*34,-4,sd*20,8],"#6e4490"); {const ta=a0+0.5*(a1-a0),bl2=2+6*fo; // 红色炮台:基座常存,爆甲后炮管伸出点亮
if(ph2>=2){ // 三阶段爆甲:犄角外壳小刺+红色炮台 ctx.save();ctx.translate(Math.cos(ta)*(R+2),Math.sin(ta)*(R+2));ctx.rotate(ta+Math.PI/2);
for(let k=0;k<3;k++)poly([sd*(25+k*7),-13-k*6,sd*(29+k*7),-22-k*6,sd*(33+k*7),-12-k*6],"#2a1a3a"); px(-2.5,-3,5,4,"#2a1a3a");
px(sd*41-3,-36,7,6,fl||"#ff3355");} px(-1.5,-3-bl2,3,bl2,fo>0.4?(fl||"#ff3355"):"#3a2248");
ctx.restore();} ctx.restore();}
ctx.globalAlpha=1;} for(let k=0;k<2;k++){const aa2=a0+(0.32+k*0.36)*(a1-a0)+Math.sin(t*0.012+k*2)*0.05; // 环面光点
const eyeA=mp!==null?clamp((mp-0.45)/0.5,0,1):1; // 核心赤瞳 px(Math.cos(aa2)*R-2,Math.sin(aa2)*R-2,4,4,"#c86bff");}
if(eyeA>0){ctx.globalAlpha=eyeA;
px(-11,-5,7,6,fl||"#ff3355");px(4,-5,7,6,fl||"#ff3355");
px(-9,-3,3,2,"#ffdfe5");px(6,-3,3,2,"#ffdfe5");
ctx.globalAlpha=1;}
} }
} }
if(flashA>0){ctx.globalAlpha=flashA;ctx.strokeStyle="#fff"; if(flashA>0){ctx.globalAlpha=flashA;ctx.strokeStyle="#fff";
@ -167,39 +174,34 @@ function drawBoss(){
ctx.fillText(b.transT>0?b.name:(b.name+" "+Math.ceil(pc*100)+"%"),W/2,22); ctx.fillText(b.transT>0?b.name:(b.name+" "+Math.ceil(pc*100)+"%"),W/2,22);
} }
/* ---- Boss 分体绘制助手 ---- */ /* ---- Boss 分体绘制助手 ---- */
function drawPupa(t,fl,cr){ // 太空原种·虫蛹cr=裂变粉化进度0~1 function drawProgenitor(t,fl,tf){ // 太空原种同一躯体连续演化tf 0=虫蛹→1=完全体),无部件凭空出现
ctx.rotate(Math.sin(t*0.05)*0.05); ctx.rotate(Math.sin(t*0.05)*0.05);
const body=[0,-40,11,-37,15,-28,13,-14,11,0,8,14,5,26,2,34,0,36,-2,34,-5,26,-8,14,-11,0,-13,-14,-15,-28,-11,-37]; const wE=Math.min(1,tf*1.2); // 展翅进度
poly(body,"#c9d6e2"); // —— 翅膀:折叠时收在躯体正后方(被身体完全遮住),自背后向两侧展开 ——
poly([0,-40,11,-37,15,-28,13,-14,11,0,8,14,5,26,2,34,0,36],"#9fb0c2"); ctx.save();
if(cr>0){ctx.globalAlpha=cr*0.85;poly(body,"#f0a0c0");ctx.globalAlpha=1;} // 身体变粉 ctx.scale(0.05+0.95*wE,(0.55+0.45*wE)*(1+Math.sin(t*0.07)*0.04*wE));
for(let i=0;i<5;i++){const wy=-24+i*11,ww=13-i*1.8;px(-ww,wy,ww*2,2,"#8498ac");}
if(cr>0.25){px(-10,-18,3,14,"#8a2a3a");px(7,-8,3,12,"#8a2a3a");} // 表皮裂开
if(cr>0.55){px(-4,-30,3,10,"#8a2a3a");px(-13,-2,3,9,"#8a2a3a");}
circ(0,-34,10,"#dde7f0");px(-9,-37,18,3,"#9fb0c2");
px(-6,-35,4,4,fl||"#43e8ff");px(2,-35,4,4,fl||"#43e8ff"); // 青眼
if(cr>0.3){ctx.globalAlpha=Math.min(1,(cr-0.3)/0.5); // 眼睛变红
px(-6,-35,4,4,"#ff3355");px(2,-35,4,4,"#ff3355");ctx.globalAlpha=1;}
px(-12,-44,3,7,"#9fb0c2");px(9,-44,3,7,"#9fb0c2");
px(-19,-16,5,12,"#7fd8ff");px(14,-16,5,12,"#7fd8ff");
}
function drawManta(t,fl,un){ // 太空原种·蝠鲼un=展翅进度0~1
const ws=0.15+0.85*un;
ctx.save();ctx.scale(ws,1+Math.sin(t*0.07)*0.04*un); // 翅膀自背后展开
poly([0,-20,-26,-14,-52,-4,-76,6,-58,12,-34,10,-16,16,0,20],"#c86aa8"); poly([0,-20,-26,-14,-52,-4,-76,6,-58,12,-34,10,-16,16,0,20],"#c86aa8");
poly([0,-20,26,-14,52,-4,76,6,58,12,34,10,16,16,0,20],"#c86aa8"); poly([0,-20,26,-14,52,-4,76,6,58,12,34,10,16,16,0,20],"#c86aa8");
poly([0,-18,-24,-12,-50,-3,-72,7,-56,9,-30,2,0,-8],"#e89cc4"); poly([0,-18,-24,-12,-50,-3,-72,7,-56,9,-30,2,0,-8],"#e89cc4");
poly([0,-18,24,-12,50,-3,72,7,56,9,30,2,0,-8],"#e89cc4"); poly([0,-18,24,-12,50,-3,72,7,56,9,30,2,0,-8],"#e89cc4");
if(un>0.6)for(const sd of[-1,1])for(let i=0;i<3;i++)px(sd*(44+i*10)-1,6+i*2,2,2,"#7dff8a"); for(const sd of[-1,1])for(let i=0;i<3;i++)px(sd*(44+i*10)-1,6+i*2,2,2,"#7dff8a"); // 翼面斑纹随翼展开
ctx.restore(); ctx.restore();
ctx.globalAlpha=Math.min(1,un*1.6); // —— 躯体:蛹壳保持同一多边形,粉色血肉晕染全身 ——
poly([0,28,-7,8,-8,-8,-5,-18,5,-18,8,-8,7,8],"#8a3a70"); const body=[0,-40,11,-37,15,-28,13,-14,11,0,8,14,5,26,2,34,0,36,-2,34,-5,26,-8,14,-11,0,-13,-14,-15,-28,-11,-37];
circ(0,-18,9,"#e8d5e0"); poly(body,"#c9d6e2");
px(-5,-19,3,4,"#3a1030");px(2,-19,3,4,"#3a1030"); poly([0,-40,11,-37,15,-28,13,-14,11,0,8,14,5,26,2,34,0,36],"#9fb0c2");
px(-5,-18,3,3,fl||"#ff3355");px(2,-18,3,3,fl||"#ff3355"); // 红瞳 if(tf>0){ctx.globalAlpha=tf*0.85;poly(body,"#f0a0c0");ctx.globalAlpha=1;} // 粉化
px(-13,-26,3,8,"#7dff8a");px(10,-26,3,8,"#7dff8a"); for(let i=0;i<5;i++){const wy=-24+i*11,ww=13-i*1.8;px(-ww,wy,ww*2,2,"#8498ac");}
for(let i=0;i<4;i++)px(-9+i*5,0,3,5,fl||"#ff3355"); const crks=[[-10,-18,14,0.12],[7,-8,12,0.28],[-4,-30,10,0.44],[-13,-2,9,0.58]]; // 裂纹逐条生长(延长,非新增)
ctx.globalAlpha=1; for(const ck of crks){const cl=Math.max(0,Math.min(1,(tf-ck[3])/0.3))*ck[2];
if(cl>0.5)px(ck[0],ck[1],3,cl,"#8a2a3a");}
circ(0,-34,10,"#dde7f0");px(-9,-37,18,3,"#9fb0c2");
px(-6,-35,4,4,fl||"#43e8ff");px(2,-35,4,4,fl||"#43e8ff"); // 眼:青→红渐变
if(tf>0.3){ctx.globalAlpha=Math.min(1,(tf-0.3)/0.5);
px(-6,-35,4,4,"#ff3355");px(2,-35,4,4,"#ff3355");ctx.globalAlpha=1;}
px(-12,-44,3,7,"#9fb0c2");px(9,-44,3,7,"#9fb0c2");
px(-19,-16,5,12,"#7fd8ff");px(14,-16,5,12,"#7fd8ff"); // 侧囊:青→荧绿渐变
if(tf>0.5){ctx.globalAlpha=(tf-0.5)*2;px(-19,-16,5,12,"#7dff8a");px(14,-16,5,12,"#7dff8a");ctx.globalAlpha=1;}
} }
function drawAssault(t,fl,swp,ph,mp){ // 暗黑突击swp=翼展角;炮管/推进器随阶段增多) function drawAssault(t,fl,swp,ph,mp){ // 暗黑突击swp=翼展角;炮管/推进器随阶段增多)
const sw=swp*Math.PI/180; const sw=swp*Math.PI/180;