starraid/star-raid/js/boss_art.js

79 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"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*30P2随第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;}}
}