79 lines
4.7 KiB
JavaScript
79 lines
4.7 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.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,"#33436a");circ(px2-1.5,0,2.5,"#55648a");
|
||
px(px2-1.5,4,3,8,"#1b2434");
|
||
px(px2-1,10,2,3,b.pedT>0?"#ffffff":(sd<0?"#b98cff":"#43e8ff"));}}
|
||
// —— 舰桥+雷达(随半壳滑开) ——
|
||
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;}}
|
||
}
|