泰伦母舰重做:锥形生物舰三阶段(裂壳露眼+触手伸出/环齿嘴展开),召唤流无弹幕,6种泰伦兵种(刀虫/爆虫自爆/孢子囊/撕裂虫/吐酸散弹/棘枪直线),触手扫击/酸蚀毒雾/骨钉
This commit is contained in:
parent
54b8a6d137
commit
6c04a143c7
@ -170,6 +170,9 @@ function updateBullets(){
|
|||||||
G.eb=G.eb.filter(b=>!b.dead);
|
G.eb=G.eb.filter(b=>!b.dead);
|
||||||
// 区域效果(电浆/引力井)
|
// 区域效果(电浆/引力井)
|
||||||
for(const z of G.zones){z.life--;
|
for(const z of G.zones){z.life--;
|
||||||
|
if(z.vy)z.y+=z.vy; // 酸雾下飘
|
||||||
|
if(z.cd>0)z.cd--;
|
||||||
|
if(z.kind==="gas"&&G.p.dead<=0&&G.p.inv<=0&&dist2(G.p.x,G.p.y,z.x,z.y)<(z.r+G.stat.hitR)*(z.r+G.stat.hitR)&&!(z.cd>0)){z.cd=45;hitPlayer(12);} // 酸雾持续伤害
|
||||||
if(z.pull)for(const e of G.enemies)if(!e.dead){
|
if(z.pull)for(const e of G.enemies)if(!e.dead){
|
||||||
const d2=dist2(z.x,z.y,e.x,e.y);
|
const d2=dist2(z.x,z.y,e.x,e.y);
|
||||||
if(d2<(z.r+44)*(z.r+44)&&d2>1){const d=Math.sqrt(d2);e.x+=(z.x-e.x)/d*0.5;e.y+=(z.y-e.y)/d*0.5;}}
|
if(d2<(z.r+44)*(z.r+44)&&d2>1){const d=Math.sqrt(d2);e.x+=(z.x-e.x)/d*0.5;e.y+=(z.y-e.y)/d*0.5;}}
|
||||||
|
|||||||
@ -9,7 +9,13 @@ const ENEMIES={
|
|||||||
gunship:{hp:55,spd:.7,score:420,r:8,gems:4,coin:.6,beh:"hover",fire:{t:"burst5",cd:160,spd:1.65},cost:4,min:6},
|
gunship:{hp:55,spd:.7,score:420,r:8,gems:4,coin:.6,beh:"hover",fire:{t:"burst5",cd:160,spd:1.65},cost:4,min:6},
|
||||||
sniper:{hp:30,spd:.6,score:300,r:6,gems:3,coin:.5,beh:"hover",fire:{t:"snipe",cd:210,spd:3.0},cost:3,min:8},
|
sniper:{hp:30,spd:.6,score:300,r:6,gems:3,coin:.5,beh:"hover",fire:{t:"snipe",cd:210,spd:3.0},cost:3,min:8},
|
||||||
rock:{hp:30,spd:1,score:40,r:8,gems:0,coin:.1,beh:"spin",fire:null,cost:0,min:0,neutral:true},
|
rock:{hp:30,spd:1,score:40,r:8,gems:0,coin:.1,beh:"spin",fire:null,cost:0,min:0,neutral:true},
|
||||||
mini:{hp:5,spd:1.8,score:60,r:4,gems:1,coin:.15,beh:"dive",fire:null,cost:.5,min:0}
|
mini:{hp:5,spd:1.8,score:60,r:4,gems:1,coin:.15,beh:"dive",fire:null,cost:.5,min:0},
|
||||||
|
gaunt:{hp:26,spd:1.45,score:150,r:6,gems:1,coin:.2,beh:"sidle",fire:null,cost:1.5,min:99}, // 泰伦刀虫(母舰专属)
|
||||||
|
sporeT:{hp:14,spd:.5,score:120,r:6,gems:1,coin:.15,beh:"drift",fire:null,death:"ring",cost:1,min:99}, // 孢子囊:慢飘,死亡酸环
|
||||||
|
ripper:{hp:6,spd:2.2,score:50,r:3.5,gems:1,coin:.1,beh:"dive",fire:null,cost:.4,min:99}, // 撕裂虫:小快速
|
||||||
|
boomer:{hp:8,spd:2.0,score:130,r:5,gems:1,coin:.15,beh:"boom",fire:null,cost:1,min:99}, // 爆虫:冲锋自爆
|
||||||
|
spitter:{hp:20,spd:.8,score:170,r:6,gems:2,coin:.25,beh:"hover",fire:{t:"acid3",cd:150,spd:1.7},cost:1.6,min:99}, // 吐酸虫:远程散弹
|
||||||
|
spinegun:{hp:22,spd:.75,score:180,r:6,gems:2,coin:.25,beh:"hover",fire:{t:"spike",cd:170,spd:3.2},cost:1.7,min:99} // 棘枪虫:骨钉直线
|
||||||
};
|
};
|
||||||
function tierN(){ // 难度层数:无尽=波次,闯关=关卡*2+小波(图鉴演示等 wave=0 场景会为负,按0计,防止hpMul产生NaN)
|
function tierN(){ // 难度层数:无尽=波次,闯关=关卡*2+小波(图鉴演示等 wave=0 场景会为负,按0计,防止hpMul产生NaN)
|
||||||
return Math.max(0,G.mode==="endless"?G.wave-1:(G.stage-1)*2+G.wave-1);
|
return Math.max(0,G.mode==="endless"?G.wave-1:(G.stage-1)*2+G.wave-1);
|
||||||
@ -52,6 +58,21 @@ function updateEnemy(e){
|
|||||||
case "dive": e.x+=e.vx*spM; e.y+=e.vy*spM; if(e.type==="kami"&&e.t%30===0){const ap=aimPt(),a=Math.atan2(ap.y-e.y,ap.x-e.x);e.vx=lerp(e.vx,Math.cos(a)*e.spd*1.4,0.15);e.vy=lerp(e.vy,Math.sin(a)*e.spd*1.4,0.15);} break;
|
case "dive": e.x+=e.vx*spM; e.y+=e.vy*spM; if(e.type==="kami"&&e.t%30===0){const ap=aimPt(),a=Math.atan2(ap.y-e.y,ap.x-e.x);e.vx=lerp(e.vx,Math.cos(a)*e.spd*1.4,0.15);e.vy=lerp(e.vy,Math.sin(a)*e.spd*1.4,0.15);} break;
|
||||||
case "hover": if(e.y<e.hy)e.y+=e.spd*1.6*spM; else e.x=clamp(e.x0+Math.sin(e.t*0.015+e.ph)*8,10,W-10); break;
|
case "hover": if(e.y<e.hy)e.y+=e.spd*1.6*spM; else e.x=clamp(e.x0+Math.sin(e.t*0.015+e.ph)*8,10,W-10); break;
|
||||||
case "spin": e.y+=e.spd*spM; e.x+=e.vx*spM; e.rot+=0.03; break;
|
case "spin": e.y+=e.spd*spM; e.x+=e.vx*spM; e.rot+=0.03; break;
|
||||||
|
case "sidle": if(e.sidleT===undefined)e.sidleT=30; // 泰伦:从母舰体内向两侧排出,随后扑向玩家
|
||||||
|
if(e.sidleT>0){e.sidleT--;e.x+=e.vx*spM;e.y+=e.vy*spM;}
|
||||||
|
else{const ap3=aimPt(),a3=Math.atan2(ap3.y-e.y,ap3.x-e.x);
|
||||||
|
e.vx=lerp(e.vx,Math.cos(a3)*e.spd,0.06);e.vy=lerp(e.vy,Math.sin(a3)*e.spd,0.06);
|
||||||
|
e.x+=e.vx*spM;e.y+=e.vy*spM;} break;
|
||||||
|
case "boom": { // 泰伦爆虫:追踪冲锋,近身自爆(酸液飞溅)
|
||||||
|
const ap4=aimPt(),a4=Math.atan2(ap4.y-e.y,ap4.x-e.x);
|
||||||
|
e.vx=lerp(e.vx,Math.cos(a4)*e.spd*1.35,0.08);e.vy=lerp(e.vy,Math.sin(a4)*e.spd*1.35,0.08);
|
||||||
|
e.x+=e.vx*spM;e.y+=e.vy*spM;
|
||||||
|
if(G.time%6===0)G.parts.push({x:e.x,y:e.y,vx:0,vy:-0.2,life:8,col:"#a8ff5c",sz:1}); // 酸液拖尾
|
||||||
|
if(dist2(e.x,e.y,G.p.x,G.p.y)<17*17){e.dead=true;
|
||||||
|
for(let i2=0;i2<8;i2++)G.parts.push({x:e.x,y:e.y,vx:Math.cos(i2*TAU/8)*rnd(0.8,1.7),vy:Math.sin(i2*TAU/8)*rnd(0.8,1.7),life:16,col:"#a8ff5c",sz:2});
|
||||||
|
SFX.hit();
|
||||||
|
if(dist2(e.x,e.y,G.p.x,G.p.y)<26*26&&G.p.dead<=0)hitPlayer(20);}
|
||||||
|
break;}
|
||||||
}
|
}
|
||||||
// 开火(独立计时器,与摆动相位完全分离)
|
// 开火(独立计时器,与摆动相位完全分离)
|
||||||
if(e.fire&&e.y>6&&e.y<H-60){
|
if(e.fire&&e.y>6&&e.y<H-60){
|
||||||
@ -74,6 +95,8 @@ function enemyFire(e){
|
|||||||
else if(f.t==="burst5")for(let i=-2;i<=2;i++)ebul(e.x,e.y+6,a0+i*0.2,f.spd,"orbO",18);
|
else if(f.t==="burst5")for(let i=-2;i<=2;i++)ebul(e.x,e.y+6,a0+i*0.2,f.spd,"orbO",18);
|
||||||
else if(f.t==="ring8")for(let i=0;i<8;i++)ebul(e.x,e.y,i/8*TAU+e.t*0.01,f.spd,"orbG",18);
|
else if(f.t==="ring8")for(let i=0;i<8;i++)ebul(e.x,e.y,i/8*TAU+e.t*0.01,f.spd,"orbG",18);
|
||||||
else if(f.t==="snipe"){ebul(e.x,e.y+4,a0,f.spd,"orbP",24);ebul(e.x,e.y+4,a0+0.05,f.spd,"orbP",24);ebul(e.x,e.y+4,a0-0.05,f.spd,"orbP",24);}
|
else if(f.t==="snipe"){ebul(e.x,e.y+4,a0,f.spd,"orbP",24);ebul(e.x,e.y+4,a0+0.05,f.spd,"orbP",24);ebul(e.x,e.y+4,a0-0.05,f.spd,"orbP",24);}
|
||||||
|
else if(f.t==="acid3")for(let i=-1;i<=1;i++)ebul(e.x,e.y+4,a0+i*0.3,f.spd,"orbG",14); // 泰伦:酸液散弹
|
||||||
|
else if(f.t==="spike")ebul(e.x,e.y+4,a0,f.spd,"spikeB",16); // 泰伦:骨钉直线
|
||||||
}
|
}
|
||||||
/* ================= 突变词缀 ================= */
|
/* ================= 突变词缀 ================= */
|
||||||
const MUTS={
|
const MUTS={
|
||||||
@ -156,7 +179,7 @@ const BOSSES=[
|
|||||||
{name:"暗黑魔碟",sub:"DARK SAUCER",hp:4500,col:"#8a5cff",r:24,rr:[30,32,34],main:"saucer",minors:["ringBig","coneFan","crossEye","dartSpiral"],phases:3},
|
{name:"暗黑魔碟",sub:"DARK SAUCER",hp:4500,col:"#8a5cff",r:24,rr:[30,32,34],main:"saucer",minors:["ringBig","coneFan","crossEye","dartSpiral"],phases:3},
|
||||||
{name:"兽人战斗月亮",sub:"ORK ROK",hp:2000,col:"#c8752a",r:26,rr:[26,29],ryy:[24,26],main:"rok",minors:["rockRain","spawnMini","snipe"],phases:2},
|
{name:"兽人战斗月亮",sub:"ORK ROK",hp:2000,col:"#c8752a",r:26,rr:[26,29],ryy:[24,26],main:"rok",minors:["rockRain","spawnMini","snipe"],phases:2},
|
||||||
{name:"黑石要塞",sub:"BLACKSTONE",hp:3400,col:"#5cff9d",r:30,rr:[34,37],ryy:[26,28],wide:1,main:"blackstone",minors:["deckGuns","crackRift","starLine"],phases:2},
|
{name:"黑石要塞",sub:"BLACKSTONE",hp:3400,col:"#5cff9d",r:30,rr:[34,37],ryy:[26,28],wide:1,main:"blackstone",minors:["deckGuns","crackRift","starLine"],phases:2},
|
||||||
{name:"泰伦虫族母舰",sub:"TYRANID HIVESHIP",hp:2800,col:"#7dff8a",r:24,rr:[24,28],ryy:[17,19],main:"hiveship",minors:["bioPlasma","spawnMini","ringBig"],phases:2}
|
{name:"泰伦虫族母舰",sub:"TYRANID HIVESHIP",hp:3200,col:"#7dff8a",r:26,rr:[26,29,32],ryy:[36,38,40],main:"hivespawn",minors:["sporeBloom","tentSweep","acidGas"],phases:3}
|
||||||
];
|
];
|
||||||
/* Boss命中判定:支持椭圆(宽扁机型),rr=x半径,ry=y半径 */
|
/* Boss命中判定:支持椭圆(宽扁机型),rr=x半径,ry=y半径 */
|
||||||
function bossHit(x,y,r){
|
function bossHit(x,y,r){
|
||||||
@ -270,6 +293,13 @@ function updateBoss(){
|
|||||||
if(b.plT===90){b.warpChg=0;bossBeam(b.x,b.y+6,b.x,H+8,b.phase>=1?24:20,"#5cff9d",10,80,30,{b,ox:0,oy:6,followX2:true,sweep:1,amp:b.phase>=1?70:50});}
|
if(b.plT===90){b.warpChg=0;bossBeam(b.x,b.y+6,b.x,H+8,b.phase>=1?24:20,"#5cff9d",10,80,30,{b,ox:0,oy:6,followX2:true,sweep:1,amp:b.phase>=1?70:50});}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(b.idx===10&&b.tent){const tn=b.tent; // 泰伦:触手扫击(预警→伸长横扫身前一带)
|
||||||
|
if(tn.warn>0){tn.warn--;
|
||||||
|
if(tn.warn<=0){tn.act=22;
|
||||||
|
const p=G.p;
|
||||||
|
if(p.dead<=0&&Math.abs(p.x-(b.x+tn.side*30))<34&&p.y>b.y+10&&p.y<b.y+88)hitPlayer(28);}}
|
||||||
|
else if(tn.act>0){tn.act--;if(tn.act<=0)b.tent=null;}
|
||||||
|
}
|
||||||
const lck=(b.laserT||0)>0; // 巨宽核心激光期间压制其他攻击
|
const lck=(b.laserT||0)>0; // 巨宽核心激光期间压制其他攻击
|
||||||
// —— 主攻击 ——
|
// —— 主攻击 ——
|
||||||
b.mainT--;
|
b.mainT--;
|
||||||
@ -343,13 +373,21 @@ function bossMain(b,def,fm){
|
|||||||
for(let k=0;k<5;k++)ebul(b.x,b.y,k*TAU/5+base,1.55,"orbG",13);
|
for(let k=0;k<5;k++)ebul(b.x,b.y,k*TAU/5+base,1.55,"orbG",13);
|
||||||
if(ph>=1)for(let k=0;k<5;k++)ebul(b.x,b.y,k*TAU/5-base+TAU/10,1.55,"orbG",13); // P2双层反向编织
|
if(ph>=1)for(let k=0;k<5;k++)ebul(b.x,b.y,k*TAU/5-base+TAU/10,1.55,"orbG",13); // P2双层反向编织
|
||||||
b.mainT=Math.round((ph>=1?38:46)/fm);break;}
|
b.mainT=Math.round((ph>=1?38:46)/fm);break;}
|
||||||
case "hiveship": // 泰伦母舰:酸液扇 + 孢子雷散布 + 周期孵化虫群
|
case "hivespawn": { // 泰伦母舰:从体内向两侧排出虫群(无弹幕);P2虫群血量变厚;P3嘴吐骨钉扇
|
||||||
for(let i=-2;i<=2;i++)ebul(b.x,b.y+14,a0+i*0.17,2.5,"orbG",14);
|
b.wvC=(b.wvC||0)+1;
|
||||||
b.spC=(b.spC||0)-1;
|
const big=b.wvC%4===0,n1=big?5+ph*2:2+ph;
|
||||||
if(b.spC<=0){for(let i=0;i<2+ph;i++)spawnEnemy("mini",b.x+rnd(-24,24),b.y+12,false);b.spC=Math.round(300/fm);}
|
for(let i=0;i<n1;i++){const sd=i%2?1:-1,tp=pick(["gaunt","gaunt","ripper","sporeT"]);
|
||||||
b.mnC=(b.mnC||0)-1;
|
spawnEnemy(tp,b.x+sd*30,b.y+rnd(-6,14),false);
|
||||||
if(b.mnC<=0){for(let i=0;i<2;i++){const s=ebul(b.x+rnd(-18,18),b.y+18,Math.PI/2+rnd(-0.25,0.25),0.8,"orbG",16);s.scale=1.7;s.r=4;}b.mnC=Math.round(150/fm);}
|
const e=G.enemies[G.enemies.length-1];
|
||||||
b.mainT=Math.round((ph?72:88)/fm);break;
|
if(tp==="sporeT"){e.x0=e.x;} // 孢子囊缓飘
|
||||||
|
else if(tp==="boomer"){e.vx=sd*rnd(0.6,1);e.vy=rnd(0.2,0.4);} // 爆虫:侧弹后直接冲锋
|
||||||
|
else if(tp!=="spitter"&&tp!=="spinegun"){e.vx=sd*rnd(0.7,1.1);e.vy=rnd(0.1,0.35);e.sidleT=rndi(26,42);e.beh="sidle";} // 近战虫侧排后扑击
|
||||||
|
if(ph>=1){e.hp*=1.5;e.maxhp*=1.5;} // P2起虫群血量变厚
|
||||||
|
spawnPart(b.x+sd*24,b.y+8,"#a8ff5c",2);}
|
||||||
|
b.mainT=Math.round((big?210:125)/fm);
|
||||||
|
if(ph>=2){for(let k=-2;k<=2;k++)ebul(b.x,b.y+30,Math.PI/2+k*0.14,2.6,"spikeB",14); // 嘴吐骨钉
|
||||||
|
b.mainT=Math.round((big?230:150)/fm);}
|
||||||
|
break;}
|
||||||
case "hive": // 母巢核心:环弹+孵化
|
case "hive": // 母巢核心:环弹+孵化
|
||||||
for(let i=0;i<10+ph*4;i++)ebul(b.x,b.y,i/(10+ph*4)*TAU+b.t*0.03,1.6+0.2*ph,"orbO");
|
for(let i=0;i<10+ph*4;i++)ebul(b.x,b.y,i/(10+ph*4)*TAU+b.t*0.03,1.6+0.2*ph,"orbO");
|
||||||
if(b.t%240<3)for(let i=0;i<1+ph;i++)spawnEnemy(ph>=2?"kami":"mini",b.x+rnd(-30,30),b.y+8,false);
|
if(b.t%240<3)for(let i=0;i<1+ph;i++)spawnEnemy(ph>=2?"kami":"mini",b.x+rnd(-30,30),b.y+8,false);
|
||||||
@ -419,7 +457,17 @@ function bossMinor(b,mk,fm){
|
|||||||
b.stC=(b.stC||0)+1;const off=(b.stC%2)*(TAU/20);
|
b.stC=(b.stC||0)+1;const off=(b.stC%2)*(TAU/20);
|
||||||
for(let k=0;k<10;k++)ebul(b.x,b.y,k*TAU/10+off,3.1,"orbG",13);
|
for(let k=0;k<10;k++)ebul(b.x,b.y,k*TAU/10+off,3.1,"orbG",13);
|
||||||
b.minorT=Math.round(215/fm);break;}
|
b.minorT=Math.round(215/fm);break;}
|
||||||
case "bioPlasma": for(let k=0;k<3;k++)ebul(b.x,b.y+12,a0+(k-1)*0.1,3.4,"orbG",14);b.minorT=Math.round(150/fm);break; // 泰伦:生物电浆三连
|
case "sporeBloom": // 泰伦:孢子囊投放(慢飘碍走位,死亡酸液环爆)
|
||||||
|
for(let i=0;i<2+b.phase;i++)spawnEnemy("sporeT",b.x+rnd(-20,20),b.y+rnd(2,16),false);
|
||||||
|
b.minorT=Math.round(280/fm);break;
|
||||||
|
case "tentSweep": // 泰伦:触手扫击(P2+):预警后伸长横扫身前一带
|
||||||
|
if(b.phase<1){b.minorT=80;break;}
|
||||||
|
if(!b.tent){b.tent={side:ap2.x<b.x?-1:1,warn:42,act:0};SFX.warn();}
|
||||||
|
b.minorT=Math.round(300/fm);break;
|
||||||
|
case "acidGas": // 泰伦:酸蚀气体(P3):触手末端释放毒雾向下飘
|
||||||
|
if(b.phase<2){b.minorT=80;break;}
|
||||||
|
for(const sd of[-1,1])G.zones.push({x:b.x+sd*14,y:b.y+30,r:13,vy:0.35,life:260,col:"#a8ff5c",kind:"gas"});
|
||||||
|
b.minorT=Math.round(240/fm);break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function hurtBoss(dmg){
|
function hurtBoss(dmg){
|
||||||
|
|||||||
72
js/render.js
72
js/render.js
@ -156,23 +156,53 @@ function drawBoss(){
|
|||||||
if(chg>0)circ(0,0,5+chg*3.5,`rgba(92,255,157,${chg*0.3})`); // 充能光晕
|
if(chg>0)circ(0,0,5+chg*3.5,`rgba(92,255,157,${chg*0.3})`); // 充能光晕
|
||||||
circ(0,0,4.5,"#0a2418");circ(0,0,3,fl||"#5cff9d");circ(0,0,1.3,"#d6ffe8"); // 亚空间核心
|
circ(0,0,4.5,"#0a2418");circ(0,0,3,fl||"#5cff9d");circ(0,0,1.3,"#d6ffe8"); // 亚空间核心
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}else if(b.idx===10){ // 泰伦母舰:生物质长舰+前触手;二阶段背甲滑开露荧光器官、触手伸长
|
}else if(b.idx===10){ // 泰伦母舰:锥形生物舰(头下尾上);P2头背甲壳裂开露眼+伸出触手;P3触手间展开环齿嘴
|
||||||
const op=mp!==null?mp:(ph2>=1?1:0);
|
let op2,op3;
|
||||||
const tl=13+op*11; // 触手连续伸长
|
if(ph2===0){op2=mp!==null?mp:0;op3=0;}
|
||||||
for(const sd of[-1,0,1]){const sw=Math.sin(t*0.06+sd*2)*3; // 触手缓摆(常存)
|
else if(ph2===1){op2=1;op3=mp!==null?mp:0;}
|
||||||
poly([sd*10-3,12,sd*10+3,12,sd*13+sw+1.5,12+tl,sd*13+sw-1.5,12+tl],"#8a4a6a");}
|
else{op2=1;op3=1;}
|
||||||
poly([0,-30,16,-22,22,-4,18,16,8,24,-8,24,-18,16,-22,-4,-16,-22],"#c8b49a"); // 生物质舰体
|
ctx.save();ctx.scale(1,1+Math.sin(t*0.05)*0.015); // 呼吸起伏
|
||||||
poly([0,-30,16,-22,22,-4,18,16,8,24,0,24],"#a8947a"); // 受光面
|
if(b.tent&&b.tent.warn>0){ctx.globalAlpha=0.13+0.09*Math.sin(t*0.3);ctx.fillStyle="#a8ff5c"; // 触手扫击预警带
|
||||||
for(let i=0;i<4;i++){const ry2=0+i*5,ww=16-i*2.5;px(-ww,ry2,ww*2,2,"#9a8a72");} // 腹肋节理
|
ctx.fillRect(b.tent.side*30-34,10,68,78);ctx.globalAlpha=1;}
|
||||||
circ(0,-8,5,"#7dff8a");circ(0,-18,3.5,"#7dff8a"); // 荧光生物器官(甲壳之下常存,裂开才露出)
|
for(const sd of[-1,0,1]){const sw=Math.sin(t*0.055+sd*1.8)*3; // 尾须缓摆
|
||||||
circ(0,-8,2,"#e8ffd0");circ(0,-18,1.5,"#e8ffd0");
|
poly([sd*8-2.5,-36,sd*8+2.5,-36,sd*11+sw,-52,sd*9+sw-1.5,-52],"#3d2f4a");
|
||||||
for(const sd of[-1,1]){ctx.save();ctx.translate(sd*op*7,0); // 背甲两瓣滑开(同一几何体平移)
|
px(sd*11+sw-1,-54,2,3,"#e8dcc0");}
|
||||||
poly([0,-30,sd*16,-22,sd*20,-6,sd*14,4,0,-2],"#5a3a6a");
|
poly([0,-44,18,-36,24,-18,20,2,12,18,6,32,0,38,-6,32,-12,18,-20,2,-24,-18,-18,-36],"#241a30"); // 锥形舰体·底
|
||||||
poly([0,-30,sd*16,-22,sd*12,-16,0,-22],"#7a5a8a");
|
poly([0,-42,15,-34,20,-18,17,0,10,16,5,30,0,35,-5,30,-10,16,-17,0,-20,-18,-15,-34],"#3d2f4a"); // 中层甲壳
|
||||||
|
poly([0,-40,6,-30,7,-12,5,4,3,16,0,22,-3,16,-5,4,-7,-12,-6,-30],"#1a1426"); // 背脊中线甲
|
||||||
|
for(let i=0;i<3;i++){const yy=-38+i*7,ww=15-i*3; // 橄榄甲片叠瓦
|
||||||
|
poly([0,yy-4,ww,yy+1,ww-3,yy+5,-(ww-3),yy+5,-ww,yy+1],i%2?"#5a6a32":"#4a5628");}
|
||||||
|
for(const sd of[-1,1])for(let i=0;i<3;i++){const yy=-30+i*12,xx=sd*(20-i*3); // 侧棘(骨白)
|
||||||
|
poly([xx,yy,xx+sd*7,yy+3,xx,yy+6],"#e8dcc0");}
|
||||||
|
for(const sd of[-1,1]){poly([sd*4,8,sd*13,4,sd*11,18,sd*6,26],"#b87a6a"); // 两侧粉肉
|
||||||
|
for(let i=0;i<3;i++)px(sd*(7+i*2)-1,9+i*5,2,4,"#8a5a4a");} // 肋纹
|
||||||
|
ctx.globalAlpha=0.35+0.3*Math.sin(t*0.09);px(-1,-34,2,44,"#7dff8a");ctx.globalAlpha=1; // 脉络搏动
|
||||||
|
if(op2>0){ctx.globalAlpha=op2; // 壳下组织:粉肉+大眼(瞳孔追玩家,P3变橙红)
|
||||||
|
circ(0,20,8,"#b87a6a");
|
||||||
|
const ex=clamp((G.p.x-b.x)*0.02,-1.5,1.5),ey=clamp((G.p.y-b.y)*0.015,-1,2);
|
||||||
|
circ(0,20,5.5,ph2>=2?"#e85c3a":"#b8e85c");
|
||||||
|
ctx.fillStyle="#0d0d14";ctx.fillRect(ex-1,17+ey,2.5,6);
|
||||||
|
circ(ex-1.5,18.5+ey,0.8,"#e8ffd0");
|
||||||
|
ctx.globalAlpha=1;}
|
||||||
|
for(const sd of[-1,1]){ctx.save();ctx.translate(sd*(op2*6+op3*5),-op3*3); // 头背甲壳两瓣:P2滑开/P3翻开
|
||||||
|
poly([0,20,sd*9,14,sd*8,28,sd*3,36,0,34],"#241a30");
|
||||||
|
poly([0,22,sd*6,17,sd*5,27,sd*2,32,0,31],"#3d2f4a");
|
||||||
ctx.restore();}
|
ctx.restore();}
|
||||||
px(-22,-8,4,7,"#3a2a1a");px(18,-8,4,7,"#3a2a1a"); // 孢子囊
|
if(op2>0){ // 触手:2长+4小(P2从裂口伸出,P3加粗;扫击侧伸长)
|
||||||
px(-21,-9,2,2,t%20<10?"#c8ff5c":"#7dff8a");px(19,-9,2,2,t%20<10?"#c8ff5c":"#7dff8a"); // 囊口荧光
|
const tent=(x0,y0,len,wd,phs,tipW)=>{const sw2=Math.sin(t*0.06+phs)*3.5;
|
||||||
px(-4,-27,3,4,fl||"#c8ff5c"); // 艏部感知器
|
for(let i2=0;i2<4;i2++){const f=i2/4;
|
||||||
|
circ(x0+sw2*f*f*2.2,y0+len*f,wd*(1-f*0.45)*(1+op3*0.3),i2%2?"#5a3a5a":"#7a4a6a");}
|
||||||
|
const fx2=x0+sw2*2.2,fy=y0+len;
|
||||||
|
poly([fx2-2*tipW,fy-2,fx2+2*tipW,fy-2,fx2,fy+6],"#e8dcc0");};
|
||||||
|
for(const sd of[-1,1]){const ext=b.tent&&b.tent.act>0&&b.tent.side===sd?2.1:1;
|
||||||
|
tent(sd*9*op2,24,(26+op3*8)*ext*op2,3.2,sd*1.7,1);}
|
||||||
|
for(const sd of[-1,1]){tent(sd*15*op2,16,12*op2,1.8,sd*2.9+1,0.6);tent(sd*4*op2,32,14*op2,1.6,sd*4.1+2,0.6);}
|
||||||
|
}
|
||||||
|
if(op3>0){const mw=9*op3; // 环齿嘴(P3展开,利齿缓慢旋动)
|
||||||
|
circ(0,30,mw,"#4a1a1a");circ(0,30,mw*0.55,"#2a0d0d");
|
||||||
|
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{ // 暗黑魔碟:核心+圆环;变形=圆环前后裂开、两半各自收缩成犄角(同一几何体连续演化);爆甲=壳板飞离、铆钉伸长成刺
|
}else{ // 暗黑魔碟:核心+圆环;变形=圆环前后裂开、两半各自收缩成犄角(同一几何体连续演化);爆甲=壳板飞离、铆钉伸长成刺
|
||||||
let open,fo,eyeG;
|
let open,fo,eyeG;
|
||||||
if(b.phase===0){open=0;fo=0;eyeG=0;}
|
if(b.phase===0){open=0;fo=0;eyeG=0;}
|
||||||
@ -402,7 +432,7 @@ function render(){
|
|||||||
ctx.save();ctx.translate(Math.round(b.x),Math.round(b.y));ctx.scale(b.scale,b.scale);
|
ctx.save();ctx.translate(Math.round(b.x),Math.round(b.y));ctx.scale(b.scale,b.scale);
|
||||||
if(b.rift>0)ctx.globalAlpha=0.5+0.4*Math.sin(G.time*0.35); // 裂隙弹预警闪烁
|
if(b.rift>0)ctx.globalAlpha=0.5+0.4*Math.sin(G.time*0.35); // 裂隙弹预警闪烁
|
||||||
ctx.drawImage(sp,-Math.round(sp.width/2),-Math.round(sp.height/2));ctx.restore();}
|
ctx.drawImage(sp,-Math.round(sp.width/2),-Math.round(sp.height/2));ctx.restore();}
|
||||||
else if(b.spr==="dartS"||b.spr==="dartB"||b.spr==="dartP"||b.spr==="shardB"){const sp=SPR[b.spr]; // 长条弹:按飞行方向偏转
|
else if(b.spr==="dartS"||b.spr==="dartB"||b.spr==="dartP"||b.spr==="shardB"||b.spr==="spikeB"){const sp=SPR[b.spr]; // 长条弹:按飞行方向偏转
|
||||||
ctx.save();ctx.translate(Math.round(b.x),Math.round(b.y));
|
ctx.save();ctx.translate(Math.round(b.x),Math.round(b.y));
|
||||||
ctx.rotate(Math.atan2(b.vy,b.vx)-Math.PI/2);
|
ctx.rotate(Math.atan2(b.vy,b.vx)-Math.PI/2);
|
||||||
ctx.drawImage(sp,-Math.round(sp.width/2),-Math.round(sp.height/2));ctx.restore();}
|
ctx.drawImage(sp,-Math.round(sp.width/2),-Math.round(sp.height/2));ctx.restore();}
|
||||||
@ -444,6 +474,14 @@ function render(){
|
|||||||
}
|
}
|
||||||
// 区域效果 / 新星环 / 水雷(按类型差异化)
|
// 区域效果 / 新星环 / 水雷(按类型差异化)
|
||||||
for(const z of G.zones){
|
for(const z of G.zones){
|
||||||
|
if(z.kind==="gas"){ // 酸雾:错落雾团(无圆界)+孢子微粒
|
||||||
|
ctx.globalAlpha=0.2;ctx.fillStyle="#7dff8a";
|
||||||
|
for(let i=0;i<5;i++){const a=i*TAU/5+z.life*0.012;
|
||||||
|
ctx.beginPath();ctx.arc(z.x+Math.cos(a)*z.r*0.42,z.y+Math.sin(a*1.7)*z.r*0.35,z.r*0.55,0,TAU);ctx.fill();}
|
||||||
|
ctx.globalAlpha=1;
|
||||||
|
if(G.time%7===0)G.parts.push({x:z.x+rnd(-1,1)*z.r*0.7,y:z.y+rnd(-1,1)*z.r*0.7,vx:0,vy:0.25,life:14,col:"#a8ff5c",sz:1});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if(z.kind==="plasma"){ // 电浆区:去除圆形区域,只保留内部窜动的电弧
|
if(z.kind==="plasma"){ // 电浆区:去除圆形区域,只保留内部窜动的电弧
|
||||||
if(G.time%4===0)zapVisual(z.x+rnd(-z.r*0.7,z.r*0.7),z.y+rnd(-z.r*0.7,z.r*0.7),z.x+rnd(-z.r*0.7,z.r*0.7),z.y+rnd(-z.r*0.7,z.r*0.7),pick(["#43e8ff","#bfeaff"]));
|
if(G.time%4===0)zapVisual(z.x+rnd(-z.r*0.7,z.r*0.7),z.y+rnd(-z.r*0.7,z.r*0.7),z.x+rnd(-z.r*0.7,z.r*0.7),z.y+rnd(-z.r*0.7,z.r*0.7),pick(["#43e8ff","#bfeaff"]));
|
||||||
if(G.time%9===0)G.parts.push({x:z.x+rnd(-z.r/2,z.r/2),y:z.y+rnd(-z.r/2,z.r/2),vx:0,vy:-0.2,life:10,col:"#43e8ff",sz:1});
|
if(G.time%9===0)G.parts.push({x:z.x+rnd(-z.r/2,z.r/2),y:z.y+rnd(-z.r/2,z.r/2),vx:0,vy:-0.2,life:10,col:"#43e8ff",sz:1});
|
||||||
|
|||||||
@ -62,6 +62,14 @@ SPR.split=bake(["....KKKK....","..KKPPPPKK..",".KPPKPPKPPK.","KPPPPPPPPPPK","KPK
|
|||||||
SPR.mini=bake([".KKKK.","KPPPPK","PKPPKP","KPPPPK",".KPPK.","..KK.."],EPAL.split);
|
SPR.mini=bake([".KKKK.","KPPPPK","PKPPKP","KPPPPK",".KPPK.","..KK.."],EPAL.split);
|
||||||
SPR.sniper=bake([".....KK.....","....KSSK....","...KSSSSK...","..KSKSSKSK..","..KSSCCSSK..",".KSSSCCSSSK.","KSKSSCCSSKSK","KSSSKSSKSSSK",".KSK.KK.KSK.","..K..KK..K..","..K.K..K.K..",".....KK....."],EPAL.sniper);
|
SPR.sniper=bake([".....KK.....","....KSSK....","...KSSSSK...","..KSKSSKSK..","..KSSCCSSK..",".KSSSCCSSSK.","KSKSSCCSSKSK","KSSSKSSKSSSK",".KSK.KK.KSK.","..K..KK..K..","..K.K..K.K..",".....KK....."],EPAL.sniper);
|
||||||
SPR.rock=bake(["....KKKK....","..KKGGGGKK..",".KGGDGGGGGK.","KGGGGDGGGGGK","KGDGGGGGGDGK","KGGGGDDGGGGK","KGGDGGGGGGGK",".KGGGGGGDGK.","..KKGGGGKK..","....KKKK...."],EPAL.rock);
|
SPR.rock=bake(["....KKKK....","..KKGGGGKK..",".KGGDGGGGGK.","KGGGGDGGGGGK","KGDGGGGGGDGK","KGGGGDDGGGGK","KGGDGGGGGGGK",".KGGGGGGDGK.","..KKGGGGKK..","....KKKK...."],EPAL.rock);
|
||||||
|
/* ---- 泰伦虫族(母舰召唤物) ---- */
|
||||||
|
SPR.gaunt=bake(["....KKKKK..","...KSSSSSK.","..KSSSSSSSK","..KSFFGGFSK",".KWSFFFFSWK",".K.KFFFFFK.","..KFFTFFFK.","...KFFFFFK.","....KFFFK..",".....KTK...","......K...."],{K:"#14101c",S:"#5a6a32",F:"#b87a6a",W:"#e8dcc0",G:"#a8ff5c",T:"#e8dcc0"}); // 刀虫:近战扑击
|
||||||
|
SPR.boomer=bake(["..KKK..",".KGGGK.","KGLLLGK","KGLCLGK","KGLLLGK",".KGGGK.","..KKK..","...K..."],{K:"#0d1a0d",G:"#4a6a3a",L:"#a8ff5c",C:"#e8ffd0"}); // 爆虫:冲锋自爆
|
||||||
|
SPR.sporeT=bake(["...KKK...","..KGGGK..",".KGLGLGK.","KGGLLLGGK","KGLGGGLGK","KGGGCGGGK",".KGGGGGK.","..K.G.K..","...K.K..."],{K:"#0d1a0d",G:"#4a6a3a",L:"#a8ff5c",C:"#e8ffd0"}); // 孢子囊:慢飘,死亡酸环
|
||||||
|
SPR.ripper=bake([".KKKK.","KFFFFK","KFGFFK","KFFFFK",".KWWK.","..KK.."],{K:"#14101c",F:"#b87a6a",G:"#a8ff5c",W:"#e8dcc0"}); // 撕裂虫:微小快速
|
||||||
|
SPR.spitter=bake(["...KKK...","..KSSSK..",".KSSSSSK.",".KSFGFSK.","KSSFFFSSK","K.SLLLS.K",".K.SLS.K.","..K.S.K..","...KKK..."],{K:"#14101c",S:"#5a6a32",F:"#b87a6a",G:"#a8ff5c",L:"#7dff8a"}); // 吐酸虫:远程散弹
|
||||||
|
SPR.spinegun=bake(["....K....","...KWK...","..KWWWK..","..KSSSK..",".KSSSSSK.",".KSFGFSK.","KSSFFFSSK",".KSKSKSK.","..KWWWK..","...KKK..."],{K:"#14101c",S:"#5a6a32",F:"#b87a6a",G:"#a8ff5c",W:"#e8dcc0"}); // 棘枪虫:骨钉直线
|
||||||
|
SPR.spikeB=bake([".W.","WKW","WKW","WKW","WKW","WKW",".W."],{K:"#3a2f26",W:"#e8dcc0"}); // 骨钉弹
|
||||||
/* 精英变体:保留明暗的金化调色 */
|
/* 精英变体:保留明暗的金化调色 */
|
||||||
function goldify(pal){
|
function goldify(pal){
|
||||||
const o={};
|
const o={};
|
||||||
@ -99,7 +107,7 @@ function orb(c1,c2){
|
|||||||
".HHCCCHH.",
|
".HHCCCHH.",
|
||||||
"...HHH..."],{H:halo,W:"#ffffff",C:c2});
|
"...HHH..."],{H:halo,W:"#ffffff",C:c2});
|
||||||
}
|
}
|
||||||
const BHALO={orbR:"#ff5566",orbP:"#b05ce8",orbG:"#5cff9d",orbO:"#ff9a3d",dartB:"#3a8cd8",flowr:"#ff8fc8",dartS:"#5ec4ff",dartP:"#b98cff",rockb:"#8a7a62",shardB:"#5cff9d"};
|
const BHALO={orbR:"#ff5566",orbP:"#b05ce8",orbG:"#5cff9d",orbO:"#ff9a3d",dartB:"#3a8cd8",flowr:"#ff8fc8",dartS:"#5ec4ff",dartP:"#b98cff",rockb:"#8a7a62",shardB:"#5cff9d",spikeB:"#e8dcc0"};
|
||||||
SPR.dartB=bake(["KCCCK",".CCC.",".CWC.","..C.."],{K:"#0d2433",C:"#3a8cd8",W:"#cfeaff"}); // 蓝色锥形敌弹(Boss弹幕)
|
SPR.dartB=bake(["KCCCK",".CCC.",".CWC.","..C.."],{K:"#0d2433",C:"#3a8cd8",W:"#cfeaff"}); // 蓝色锥形敌弹(Boss弹幕)
|
||||||
SPR.flowr=bake([
|
SPR.flowr=bake([
|
||||||
"....P....",".P..P..P.","..PPPPP..",".PPWWWPP.","PPPWWWPPP",
|
"....P....",".P..P..P.","..PPPPP..",".PPWWWPP.","PPPWWWPPP",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user