触手扫击移植demo验证版:角度制60°扇形挥鞭(前摇后拉蓄力+发光聚能/加速挥出+残影/顿挫/收回),触手即碰撞体(点-线段连续判定,渲染判定同源),刀尖朝向跟随切线,删预警带
This commit is contained in:
parent
a9398a5174
commit
f21b7e24fa
136
demo/tentacle-sweep.html
Normal file
136
demo/tentacle-sweep.html
Normal file
@ -0,0 +1,136 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>泰伦触手扫击 · 动作设计 Demo v2</title>
|
||||
<style>
|
||||
html,body{margin:0;background:#05070d;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;font-family:monospace}
|
||||
canvas{border-radius:8px;box-shadow:0 0 40px #0a2a1a}
|
||||
#tip{color:#5a7a6a;font-size:12px;margin-top:10px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="cv" width="600" height="330"></canvas>
|
||||
<div id="tip">右侧触手:前摇向右后拉蓄力(发光+聚能粒子)→ 从右下向左下 60° 扇形挥鞭(残影轨迹)→ 顿挫收回 · 判定=根部圆心扇形</div>
|
||||
<script>
|
||||
const cv=document.getElementById('cv'),ctx=cv.getContext('2d');
|
||||
const W=600,H=330;
|
||||
const ROOT={x:352,y:56},ROOT2={x:248,y:56};
|
||||
const SEG=7,BASE_LEN=148;
|
||||
// 时间线(帧):待机0.9s → 前摇0.83s → 扫击0.47s → 顿挫0.28s → 收回0.67s
|
||||
const T_IDLE=55,T_WIND=105,T_STRIKE=133,T_HOLD=150,T_REC=190,T_LOOP=T_REC;
|
||||
const A_MAX=0.73; // 前摇后拉角(+42°,扫击起点)
|
||||
const A_END=-0.58; // 扫击终点(-33°),覆盖 ±30° = 60° 扇形
|
||||
const rnd=(a,b)=>a+Math.random()*(b-a);
|
||||
function circ(x,y,r,c){ctx.fillStyle=c;ctx.beginPath();ctx.arc(x,y,Math.max(0.1,r),0,Math.PI*2);ctx.fill();}
|
||||
function segDist2(px,py,ax,ay,bx,by){ // 点到线段距离平方(触手=连续碰撞体,无节段间隙)
|
||||
const dx=bx-ax,dy=by-ay,L2=dx*dx+dy*dy||1;
|
||||
const tt=Math.max(0,Math.min(1,((px-ax)*dx+(py-ay)*dy)/L2));
|
||||
const cx=ax+dx*tt,cy=ay+dy*tt;
|
||||
return (px-cx)*(px-cx)+(py-cy)*(py-cy);
|
||||
}
|
||||
// —— 动作采样:输出扫掠角(弧度,0=正下方,右正左负)、伸缩、发光 ——
|
||||
function sample(tt){
|
||||
tt=((tt%T_LOOP)+T_LOOP)%T_LOOP;
|
||||
const idle=Math.sin(tt*0.06)*0.07;
|
||||
if(tt<T_IDLE)return{ang:idle,stretch:1,glow:0,ph:0};
|
||||
if(tt<T_WIND){const f=(tt-T_IDLE)/(T_WIND-T_IDLE),e=f*f; // 前摇:向右后拉过伸,发光渐强+绷紧微颤
|
||||
return{ang:idle*(1-f)+A_MAX*e+Math.sin(tt*0.9)*0.012*e,stretch:1+e*0.15,glow:f,ph:1};}
|
||||
if(tt<T_STRIKE){const f=(tt-T_WIND)/(T_STRIKE-T_WIND),e=f*f*f; // 扫击:加速挥出(从右下到左下)
|
||||
return{ang:A_MAX-e*(A_MAX-A_END),stretch:1.15+e*0.45,glow:1,ph:2};}
|
||||
if(tt<T_HOLD){const f=(tt-T_STRIKE)/(T_HOLD-T_STRIKE); // 顿挫:末端微颤衰减
|
||||
return{ang:A_END+Math.sin(tt*1.2)*0.05*(1-f),stretch:1.6,glow:1,ph:3};}
|
||||
const f=(tt-T_HOLD)/(T_REC-T_HOLD),e=1-(1-f)*(1-f); // 收回
|
||||
return{ang:A_END+(idle-A_END)*e,stretch:1.6-0.6*e,glow:1-f,ph:4};
|
||||
}
|
||||
function segPos(i,tt){ // 节段 i(0=根,SEG-1=尖),逐节延迟形成鞭弧
|
||||
const s=sample(tt-i*2.2),f=i/(SEG-1),L=BASE_LEN*s.stretch*f;
|
||||
return{x:ROOT.x+Math.sin(s.ang)*L,y:ROOT.y+Math.cos(s.ang)*L,s};
|
||||
}
|
||||
let t=0,trail=[],parts=[];
|
||||
let ships=[
|
||||
{x:421,y:211,ang:"+24°",dead:false,hitT:0}, // 扫击前段命中
|
||||
{x:293,y:247,ang:"-17°",dead:false,hitT:0}, // 扫击后段命中
|
||||
{x:529,y:169,ang:"扇外",dead:false,hitT:0} // 扇形外安全
|
||||
];
|
||||
const PHN=["待机 IDLE","前摇 WINDUP · 后拉蓄力","扫击 STRIKE!","顿挫 HIT-STOP","收回 RECOVER"];
|
||||
const PHC=["#5a7a6a","#ffd23d","#ff5566","#e8dcc0","#43e8ff"];
|
||||
function ship(s,col,label){
|
||||
if(s.dead)return;
|
||||
ctx.fillStyle=col;ctx.beginPath();
|
||||
ctx.moveTo(s.x,s.y-6);ctx.lineTo(s.x-5,s.y+5);ctx.lineTo(s.x+5,s.y+5);ctx.closePath();ctx.fill();
|
||||
circ(s.x,s.y-1,1.5,"#fff");
|
||||
ctx.font="8px monospace";ctx.fillStyle="#3a4a5a";ctx.textAlign="center";ctx.fillText(label,s.x,s.y+14);
|
||||
}
|
||||
function draw(){
|
||||
t++;
|
||||
ctx.fillStyle="#070a14";ctx.fillRect(0,0,W,H);
|
||||
for(let i=0;i<40;i++)circ((i*137)%W,(i*89)%H,0.7,"#141d33");
|
||||
const cur=sample(t);
|
||||
// —— 母舰头部示意 ——
|
||||
circ(300,20,58,"#241a30");circ(300,14,46,"#3d2f4a");
|
||||
ctx.fillStyle="#1a1426";ctx.fillRect(244,40,112,20);
|
||||
circ(ROOT2.x,ROOT2.y,9,"#241a30");circ(ROOT.x,ROOT.y,9,"#241a30");
|
||||
// —— 左侧待机触手(对比) ——
|
||||
for(let i=SEG-1;i>=0;i--){const f=i/(SEG-1);
|
||||
circ(ROOT2.x+Math.sin(t*0.06+1.7)*10*f*f,ROOT2.y+BASE_LEN*f,7.5-f*4.5,i%2?"#7a4a6a":"#5a3a5a");}
|
||||
// —— 触手节点 ——
|
||||
const pts=[];for(let i=0;i<SEG;i++)pts.push(segPos(i,t));
|
||||
// —— 残影轨迹(扫击期记录,扇形弧带) ——
|
||||
if(cur.ph===2){trail.push(pts.map(p=>({x:p.x,y:p.y})));if(trail.length>10)trail.shift();}
|
||||
else if(trail.length)trail.shift();
|
||||
trail.forEach((h,hi)=>{const a=(hi+1)/trail.length*0.2;
|
||||
ctx.globalAlpha=a;for(let i=1;i<SEG;i++){const f=i/(SEG-1);circ(h[i].x,h[i].y,(7.5-f*4.5)*0.85,"#a8ff5c");}ctx.globalAlpha=1;});
|
||||
// —— 前摇聚能粒子(被触手吸入) ——
|
||||
if(cur.ph===1&&t%3===0){const tp=pts[4];
|
||||
parts.push({x:tp.x+rnd(-55,55),y:tp.y+rnd(-35,55),sx:tp.x,sy:tp.y,vx:0,vy:0,life:18,suck:1});}
|
||||
// —— 扫击触手本体 ——
|
||||
for(let i=SEG-1;i>=0;i--){const p=pts[i],f=i/(SEG-1),r=7.5-f*4.5;
|
||||
if(p.s.glow>0.15){ctx.globalAlpha=p.s.glow*0.28;circ(p.x,p.y,r+3.5,"#a8ff5c");ctx.globalAlpha=1;}
|
||||
circ(p.x,p.y,r,i%2?"#7a4a6a":"#5a3a5a");}
|
||||
// —— 骨白刀尖(朝向跟随触手末端方向) ——
|
||||
const p1=pts[SEG-2],p2=pts[SEG-1],ta=Math.atan2(p2.y-p1.y,p2.x-p1.x);
|
||||
ctx.save();ctx.translate(p2.x,p2.y);ctx.rotate(ta-Math.PI/2);
|
||||
ctx.fillStyle="#e8dcc0";ctx.beginPath();
|
||||
ctx.moveTo(-4,-2);ctx.lineTo(4,-2);ctx.lineTo(0,10);ctx.closePath();ctx.fill();
|
||||
ctx.restore();
|
||||
// —— 扫击洒落酸液 ——
|
||||
if(cur.ph===2&&t%2===0)parts.push({x:pts[5].x,y:pts[5].y,vx:rnd(-0.6,0.6),vy:rnd(0.5,1.5),life:26});
|
||||
// —— 触手即碰撞体:扫击+顿挫期间(尖端实际扫完全程)整条触手与飞船碰撞 ——
|
||||
if(cur.ph===2||cur.ph===3)for(const s of ships){if(s.dead)continue;
|
||||
for(let i=1;i<SEG;i++){const f=i/(SEG-1),sr=(7.5-f*4.5)+5;
|
||||
if(segDist2(s.x,s.y,pts[i-1].x,pts[i-1].y,pts[i].x,pts[i].y)<sr*sr){s.dead=true;s.hitT=45;
|
||||
for(let j=0;j<12;j++)parts.push({x:s.x,y:s.y,vx:rnd(-1.6,1.6),vy:rnd(-1.6,1.6),life:22,red:1});
|
||||
break;}}}
|
||||
if(t%T_LOOP===1)for(const s of ships){s.dead=false;s.hitT=0;}
|
||||
// —— 粒子 ——
|
||||
for(let i=parts.length-1;i>=0;i--){const p=parts[i];p.life--;
|
||||
if(p.suck){p.vx+=(p.sx-p.x)*0.006;p.vy+=(p.sy-p.y)*0.006;}
|
||||
p.x+=p.vx;p.y+=p.vy;
|
||||
if(p.life<=0){parts.splice(i,1);continue;}
|
||||
ctx.globalAlpha=Math.min(1,p.life/16);
|
||||
circ(p.x,p.y,p.red?2:1.6,p.red?"#ff5566":"#a8ff5c");ctx.globalAlpha=1;}
|
||||
// —— 演示飞船 ——
|
||||
for(const s of ships){ship(s,s.ang==="扇外"?"#3a5a6a":"#43e8ff",s.ang);
|
||||
if(s.hitT>0){s.hitT--;ctx.globalAlpha=Math.min(1,s.hitT/20);
|
||||
ctx.font="bold 12px monospace";ctx.fillStyle="#ff5566";ctx.textAlign="center";
|
||||
ctx.fillText("HIT!",s.x,s.y-14);ctx.globalAlpha=1;}}
|
||||
// —— 阶段标签 ——
|
||||
ctx.font="bold 13px monospace";ctx.fillStyle=PHC[cur.ph];ctx.textAlign="left";
|
||||
ctx.fillText(PHN[cur.ph],16,26);
|
||||
ctx.font="10px monospace";ctx.fillStyle="#3a4a5a";
|
||||
ctx.fillText("frame "+(t%T_LOOP)+" / "+T_LOOP,16,42);
|
||||
// —— 底部时间轴 ——
|
||||
const ax=16,aw=W-32,ay=H-18;
|
||||
const seg3=[[0,T_IDLE,"#1a2433"],[T_IDLE,T_WIND,"#8a7420"],[T_WIND,T_STRIKE,"#a03040"],[T_STRIKE,T_REC,"#2a6a80"]];
|
||||
for(const[a0,a1,c]of seg3){ctx.fillStyle=c;ctx.fillRect(ax+a0/T_LOOP*aw,ay,(a1-a0)/T_LOOP*aw,8);}
|
||||
ctx.fillStyle="#fff";ctx.fillRect(ax+(t%T_LOOP)/T_LOOP*aw-1,ay-2,2,12);
|
||||
ctx.fillStyle="#3a4a5a";ctx.font="9px monospace";
|
||||
ctx.fillText("待机",ax+8,ay+7);ctx.fillText("前摇0.83s",ax+T_IDLE/T_LOOP*aw+6,ay+7);
|
||||
ctx.fillText("扫击0.47s",ax+T_WIND/T_LOOP*aw+4,ay+7);ctx.fillText("顿挫+收回",ax+T_STRIKE/T_LOOP*aw+6,ay+7);
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
draw();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -36,6 +36,25 @@ function spawnEnemy(type,x,y,elite){
|
||||
if(e.beh==="spin"){e.vx=rnd(-0.5,0.5);e.rot=rnd(0,TAU);}
|
||||
G.enemies.push(e);
|
||||
}
|
||||
/* ---- 泰伦触手扫击:角度制扇形动作(demo验证版移植,渲染与判定同源) ---- */
|
||||
function tentPose(tn,side,tB){ // 返回{ang(0=正下,side向为正),stretch,glow}
|
||||
const idle=Math.sin(tB*0.06)*0.07*side;
|
||||
if(tn.warn>0){const f=1-tn.warn/50,e=f*f; // 前摇:向扫击反方向后拉蓄力
|
||||
return{ang:idle*(1-f)+side*0.73*e+Math.sin(tB*0.9)*0.012*e,stretch:1+e*0.15,glow:f};}
|
||||
if(tn.act>17){const f=(45-tn.act)/28,e=f*f*f; // 扫击:加速挥出(右下→左下60°扇形)
|
||||
return{ang:side*(0.73-e*1.31),stretch:1.15+e*0.45,glow:1};}
|
||||
if(tn.act>0){return{ang:side*(-0.58)+Math.sin(tB*1.2)*0.05*(tn.act/17),stretch:1.6,glow:1};} // 顿挫
|
||||
const f=1-tn.rec/40,e=1-(1-f)*(1-f); // 收回
|
||||
return{ang:side*(-0.58)+(idle-side*(-0.58))*e,stretch:1.6-0.6*e,glow:1-e};}
|
||||
function tentSegs(b,side,opF){ // 触手7节局部坐标(相对Boss中心),逐节延迟形成鞭弧
|
||||
const pts=[];opF=opF===undefined?1:opF;
|
||||
for(let i=0;i<7;i++){
|
||||
let ang=Math.sin((b.t-i*2.2)*0.06)*0.07*side,stretch=1,glow=0;
|
||||
if(b.tent){const s=tentPose(b.tent,side,b.t-i*2.2);ang=s.ang;stretch=s.stretch;glow=s.glow;}
|
||||
const f=i/6,L=40*stretch*f*opF;
|
||||
pts.push({x:side*9+Math.sin(ang)*L,y:24+Math.cos(ang)*L,glow});
|
||||
}
|
||||
return pts;}
|
||||
/* ---- 敌机行为 ---- */
|
||||
function updateEnemy(e){
|
||||
e.t++; if(e.flash>0)e.flash--; if(e.hpt>0)e.hpt--;
|
||||
@ -293,13 +312,20 @@ 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.idx===10&&b.tent){const tn=b.tent; // 泰伦:触手扫击(预警→横扫扇形,扫至中段判定)
|
||||
if(tn.warn>0){tn.warn--;if(tn.warn<=0){tn.act=30;tn.hitDone=false;}}
|
||||
if(b.idx===10&&b.tent){const tn=b.tent; // 泰伦:触手扫击(前摇→横扫→顿挫→收回;触手即碰撞体)
|
||||
if(tn.warn>0){tn.warn--;if(tn.warn<=0){tn.act=45;tn.hitDone=false;}}
|
||||
else if(tn.act>0){tn.act--;
|
||||
if(!tn.hitDone&&tn.act<=15){tn.hitDone=true;
|
||||
if(!tn.hitDone){ // 扫击+顿挫全期:玩家与触手各节线段做点-线段碰撞
|
||||
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);}
|
||||
if(tn.act<=0)b.tent=null;}
|
||||
if(p.dead<=0){const pts=tentSegs(b,tn.side),lx=p.x-b.x,ly=p.y-b.y;
|
||||
for(let i=1;i<7;i++){const f=i/6,sr=3.2*(1-f*0.45)+G.stat.hitR+1;
|
||||
const ax=pts[i-1].x,ay=pts[i-1].y,dx=pts[i].x-ax,dy=pts[i].y-ay,L2=dx*dx+dy*dy||1;
|
||||
const tt=clamp(((lx-ax)*dx+(ly-ay)*dy)/L2,0,1),cx=ax+dx*tt,cy=ay+dy*tt;
|
||||
if(dist2(lx,ly,cx,cy)<sr*sr){tn.hitDone=true;hitPlayer(28);break;}}}
|
||||
}
|
||||
if(tn.act<=0)tn.rec=40;
|
||||
}
|
||||
else if(tn.rec>0){tn.rec--;if(tn.rec<=0)b.tent=null;}
|
||||
}
|
||||
const lck=(b.laserT||0)>0; // 巨宽核心激光期间压制其他攻击
|
||||
// —— 主攻击 ——
|
||||
@ -462,10 +488,10 @@ function bossMinor(b,mk,fm){
|
||||
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+):预警后伸长横扫身前一带
|
||||
case "tentSweep": // 泰伦:触手扫击(P2+):前摇后拉蓄力→60°扇形挥鞭(触手即碰撞体)
|
||||
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;
|
||||
if(!b.tent){b.tent={side:ap2.x<b.x?-1:1,warn:50,act:0,rec:0,trail:null};SFX.warn();}
|
||||
b.minorT=Math.round(330/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*16,y:b.y+30,r:19,vy:0.75,life:520,col:"#a8ff5c",kind:"gas"});
|
||||
|
||||
33
js/render.js
33
js/render.js
@ -162,8 +162,6 @@ function drawBoss(){
|
||||
else if(ph2===1){op2=1;op3=mp!==null?mp:0;}
|
||||
else{op2=1;op3=1;}
|
||||
ctx.save();ctx.scale(1,1+Math.sin(t*0.05)*0.015); // 呼吸起伏
|
||||
if(b.tent&&b.tent.warn>0){ctx.globalAlpha=0.13+0.09*Math.sin(t*0.3);ctx.fillStyle="#a8ff5c"; // 触手扫击预警带
|
||||
ctx.fillRect(b.tent.side*30-34,10,68,78);ctx.globalAlpha=1;}
|
||||
for(const sd of[-1,0,1]){const sw=Math.sin(t*0.055+sd*1.8)*3; // 尾须缓摆
|
||||
poly([sd*8-2.5,-36,sd*8+2.5,-36,sd*11+sw,-52,sd*9+sw-1.5,-52],"#3d2f4a");
|
||||
px(sd*11+sw-1,-54,2,3,"#e8dcc0");}
|
||||
@ -188,16 +186,27 @@ function drawBoss(){
|
||||
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();}
|
||||
if(op2>0){ // 触手:2长+4小(P2从裂口伸出,P3加粗;扫击侧伸长)
|
||||
const tent=(x0,y0,len,wd,phs,tipW,swF,swS)=>{const sw2=Math.sin(t*0.06+phs)*3.5;
|
||||
const bx=swF!=null?(swF*2-1)*30*(swS||1):0; // 扫击:尖端横扫偏转
|
||||
for(let i2=0;i2<4;i2++){const f=i2/4;
|
||||
circ(x0+sw2*f*f*2.2+bx*f*f,y0+len*f,wd*(1-f*0.45)*(1+op3*0.3),i2%2?"#5a3a5a":"#7a4a6a");}
|
||||
const fx2=x0+sw2*2.2+bx,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 swp=b.tent&&b.tent.act>0&&b.tent.side===sd?1-b.tent.act/30:null; // 扫击侧:横扫扇形动画
|
||||
tent(sd*9*op2,24,(26+op3*8)*(swp!=null?1.8:1)*op2,3.2,sd*1.7,1,swp,sd);}
|
||||
for(const sd of[-1,1]){tent(sd*15*op2,16,12*op2,1.8,sd*2.9+1,0.6,null,0);tent(sd*4*op2,32,14*op2,1.6,sd*4.1+2,0.6,null,0);}
|
||||
if(op2>0){ // 触手:2长(角度制扇形摆荡,与判定同源)+4小
|
||||
for(const sd of[-1,1]){
|
||||
const pts=tentSegs(b,sd,op2),gl=pts[3].glow||0,sweeping=b.tent&&b.tent.side===sd;
|
||||
if(sweeping&&b.tent.act>17){b.tent.trail=b.tent.trail||[];b.tent.trail.push(pts.map(p=>({x:p.x,y:p.y})));if(b.tent.trail.length>10)b.tent.trail.shift();} // 扫击记录残影
|
||||
else if(sweeping&&b.tent.trail&&b.tent.trail.length)b.tent.trail.shift();
|
||||
if(sweeping&&b.tent.trail){const tr=b.tent.trail;
|
||||
for(let hi=0;hi<tr.length;hi++){const a=(hi+1)/tr.length*0.2;ctx.globalAlpha=a;
|
||||
for(let i=1;i<7;i++){const f=i/6;circ(tr[hi][i].x,tr[hi][i].y,3.2*(1-f*0.45)*0.85,"#a8ff5c");}ctx.globalAlpha=1;}}
|
||||
for(let i=6;i>=0;i--){const p=pts[i],f=i/6,r=Math.max(0.5,3.2*(1-f*0.45)*(1+op3*0.3));
|
||||
if(gl>0.15){ctx.globalAlpha=gl*0.28;circ(p.x,p.y,r+2,"#a8ff5c");ctx.globalAlpha=1;}
|
||||
circ(p.x,p.y,r,i%2?"#7a4a6a":"#5a3a5a");}
|
||||
const p1=pts[5],p2=pts[6],ta=Math.atan2(p2.y-p1.y,p2.x-p1.x); // 骨白刀尖:朝向跟随末端切线
|
||||
ctx.save();ctx.translate(p2.x,p2.y);ctx.rotate(ta-Math.PI/2);
|
||||
poly([-2.5,-1.5,2.5,-1.5,0,6],"#e8dcc0");
|
||||
ctx.restore();
|
||||
}
|
||||
if(b.tent&&b.tent.warn>0&&G.time%3===0){const pts2=tentSegs(b,b.tent.side,op2); // 前摇聚能粒子
|
||||
G.parts.push({x:b.x+pts2[4].x+rnd(-24,24),y:b.y+pts2[4].y+rnd(-14,24),vx:0,vy:0,life:18,col:"#a8ff5c",sz:1,suck:{x:b.x+pts2[4].x,y:b.y+pts2[4].y}});}
|
||||
for(const sd of[-1,1]){const tentS=(x0,y0,len,wd,phs)=>{const sw2=Math.sin(t*0.06+phs)*3; // 4条小触手
|
||||
for(let i2=0;i2<3;i2++){const f=i2/3;circ(x0+sw2*f*f*2,y0+len*f,wd*(1-f*0.4)*(1+op3*0.3),i2%2?"#5a3a5a":"#7a4a6a");}};
|
||||
tentS(sd*15*op2,16,12*op2,1.8,sd*2.9+1);tentS(sd*4*op2,32,14*op2,1.6,sd*4.1+2);}
|
||||
}
|
||||
if(op3>0){const mw=9*op3; // 环齿嘴(P3展开,利齿缓慢旋动)
|
||||
circ(0,30,mw,"#4a1a1a");circ(0,30,mw*0.55,"#2a0d0d");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user