aardio 文档
aardio 范例: 鹈鹕之门 - 当场惊跌坐,大的要来了!
import win.ui;
/*DSG{{*/
var winform = win.form(text="鹈鹕之门 - 当场惊跌坐,大的要来了!";right=1060;bottom=720;bgcolor=0x081523;border="dialog frame";max=false)
winform.add(
pelicanCanvas={cls="plus";left=0;top=0;right=1060;bottom=720;clipBk=false;db=1;dl=1;dr=1;dt=1;notify=1;z=1}
)
/*}}*/
/*
鹈鹕之门
- 模型鱼被越来越大的版本泡泡托向 AGI? 漩涡。
- 等泡泡经过淡蓝色 TEST LINE,点击任意位置;鹈鹕会把线路上从近到远的第一个物体戳中。
- 版本越高,泡泡越大、越快、越靠近 AGI,也越容易彼此接触并触发连锁爆破。
- 模型鱼全部使用同等可爱的普通鱼造型;HYPE 河豚、幻觉水母、技术债旧靴子、基准泄漏仅代表行业现象。
- 默认启用舒缓规则:漏掉模型鱼会依次点亮 A → G → I,三个字母全亮才失败。
- 将 RELAXED_AGI_MODE 改为 false,即可切换为“一条模型鱼进入 AGI 立即失败”的硬核规则。
- M 切换事件音效,R 重开当前关。玩家的实际游戏动作始终只有“点击任意位置”。
*/
var CANVAS_W=1060;
var CANVAS_H=720;
var CX=620;
var CY=280;
var ORBIT_Y=0.72;
var CAPTURE_RADIUS=64;
var LINE_X=240;
var LINE_Y=520;
var LINE_LEN=790;
var RELAXED_AGI_MODE=true;
var lineVx=CX-LINE_X;
var lineVy=CY-LINE_Y;
var lineDistance=math.sqrt(lineVx*lineVx+lineVy*lineVy);
var LINE_DX=lineVx/lineDistance;
var LINE_DY=lineVy/lineDistance;
var LINE_NX=-LINE_DY;
var LINE_NY=LINE_DX;
var LINE_END_X=LINE_X+LINE_DX*LINE_LEN;
var LINE_END_Y=LINE_Y+LINE_DY*LINE_LEN;
var STATE_PLAY=1;
var STATE_WIN=2;
var STATE_FAILED=3;
var VERSION_LABELS=["1.2","2.5","3.0","AGI?"];
var VERSION_SIZES=[31,38,46,55];
var VERSION_COLORS=[0xFF63D9FF,0xFF8D8CFF,0xFFFF73C9,0xFFFFC85B];
var PHASES=[1.72,2.05,3.54,4.66,5.78,0.50,0.83,3.92];
var levels=[
{name="第一次基准测试";subtitle="友情提醒:等泡泡穿过 TEST LINE";fish=4;inward=14.4;spin=0.61;accent=0xFF5BE9FF;specials=[]},
{name="版本开始膨胀";subtitle="近点更好戳,更易连爆";fish=5;inward=15.2;spin=0.65;accent=0xFF8EA1FF;specials=[{kind="hype";at=0.45}]},
{name="透明的干扰项";subtitle="幻觉水母只会挡你一次";fish=5;inward=16.0;spin=0.69;accent=0xFFC387FF;specials=[{kind="jelly";at=0.75}]},
{name="历史包袱";subtitle="技术债会反弹,但也能一嘴撞飞";fish=6;inward=16.8;spin=0.73;accent=0xFFFFA56D;specials=[{kind="hype";at=0.45},{kind="boot";at=1.65}]},
{name="基准开始泄漏";subtitle="LEAK 会让附近模型突然加速升级";fish=6;inward=17.7;spin=0.77;accent=0xFF52F2C4;specials=[{kind="jelly";at=0.55},{kind="leak";at=1.45}]},
{name="发布会前夜";subtitle="大的要来了,小的要去了!";fish=7;inward=18.6;spin=0.81;accent=0xFFFFD35E;specials=[{kind="hype";at=0.35},{kind="boot";at=1.75},{kind="leak";at=2.65}]}
];
//不借用任何真实模型名字;差异只来自颜色、鳍纹与通用能力暗示。
var modelDefs=[
{name="推理鳍";color=0xFF62D9FF;mark=1},
{name="视觉鳞";color=0xFFFF78B8;mark=2},
{name="代码尾";color=0xFF8D8CFF;mark=3},
{name="长文鱼";color=0xFF62E2A5;mark=4},
{name="工具鳍";color=0xFFFFB85C;mark=5},
{name="多模眼";color=0xFFEF7BFF;mark=6},
{name="规划尾";color=0xFF76A9FF;mark=7}
];
var game={
level=1;state=STATE_PLAY;pulse=0;elapsed=0;intro=0;
entities=[];particles=[];shards=[];shocks=[];splashes=[];feathers=[];
score=0;leaks=0;saved=0;shotId=0;chainCount=0;chainTime=0;
cooldown=0;stun=0;strike=null;neckWobble=0;screenShake=0;
status="";statusTime=0;winDelay=0;resultTime=0;
gagText="";gagTime=0;gagMax=0;gagColor=0xFFFFFFFF;hypeSeen=0;finalCue=0;
mega=null;megaShotId=-1;hypeShotId=-1;pelicanBlast=0;flash=0;
muted=false;nextEntityId=0;lineReady=false
};
var CACHE_SCALE=winform.dpiScale(1);
var sceneCache;
var sceneDirty=true;
var stars=[];
for(i=1;92){
table.push(stars,{x=math.random()*CANVAS_W;y=math.random()*CANVAS_H;size=0.5+math.random()*1.4;alpha=24+math.random(0,70)});
}
//复用字体,避免逐帧反复创建字体对象。Tahoma 会自动转换为 Segoe UI
var FONT_10=gdip.font("Tahoma",10);
var FONT_11=gdip.font("Tahoma",11);
var FONT_12=gdip.font("Tahoma",12);
var FONT_13=gdip.font("Tahoma",13);
var FONT_12B=gdip.font("Tahoma",12,1/*_GdipFontStyleBold*/);
var FONT_14B=gdip.font("Tahoma",14,1);
var FONT_18B=gdip.font("Tahoma",18,1);
var FONT_24B=gdip.font("Tahoma",24,1);
var FONT_32B=gdip.font("Tahoma",32,1);
var FONT_44B=gdip.font("Tahoma",44,1);
//把昂贵的大面积半透明爆发预绘为小型透明精灵;高 DPI 下每帧只缩放一次位图。
import gdip.imageAttributes;
var megaSprite=gdip.bitmap(640,640);
var megaSpriteGraphics=gdip.graphics(megaSprite);
megaSpriteGraphics.clear(0x00000000);megaSpriteGraphics.smoothingMode=4;
var megaAura=gdip.solidBrush(0x2AFFB52E);megaSpriteGraphics.fillCircle(megaAura,320,320,220);megaAura.delete();
var megaCore=gdip.solidBrush(0x76FFFFB4);megaSpriteGraphics.fillCircle(megaCore,320,320,108);megaCore.delete();
for(i=0;7){
var a=i*math.pi/4;var ray=gdip.pen(0x52FFE887,4);
megaSpriteGraphics.drawLine(ray,320+math.cos(a)*48,320+math.sin(a)*48,320+math.cos(a)*310,320+math.sin(a)*310);ray.delete();
}
var megaRings=[90,175,270];
for(i,r in megaRings){
var ring=gdip.pen(i==1 ? 0xC3FFFFFF : 0xC3FFD866,7-i*1.3);
megaSpriteGraphics.drawCircle(ring,320,320,r);ring.delete();
}
megaSpriteGraphics.delete();megaSpriteGraphics=null;
var megaImageAttributes=gdip.imageAttributes();
import sys.midiOut;
var midiOut=sys.midiOut();
if(midiOut) midiOut.setVelocity(82);
// -------------------- 通用辅助 --------------------
var alphaColor=function(color,alpha){
return (math.clamp(math.floor(alpha),0,255)<<24)|(color&0xFFFFFF);
}
var shadeColor=function(color,amount){
var r=math.clamp(((color>>16)&0xFF)+amount,0,255);
var g=math.clamp(((color>>8)&0xFF)+amount,0,255);
var b=math.clamp((color&0xFF)+amount,0,255);
return 0xFF000000|(math.floor(r)<<16)|(math.floor(g)<<8)|math.floor(b);
}
var levelData=function(){ return levels[game.level]; }
var setStatus=function(text,duration){
game.status=text;game.statusTime=duration;
}
var setGag=function(text,duration,color){
game.gagText=text;game.gagTime=duration;game.gagMax=duration;
game.gagColor=color : 0xFFFFFFFF;
}
var drawText=function(graphics,text,font,x,y,w,h,color,align){
var brush=gdip.solidBrush(color);
var format=gdip.stringFormat();
format.align=align : 0;
format.lineAlign=1;
graphics.drawString(text,font,::RECTF(x,y,w,h),format,brush);
format.delete();brush.delete();
}
//简谱中的下划线表示短音时值;sys.midiOut 会在时值结束时自动释放音符。
var playNote=function(instrument,note,duration){
if(midiOut && !game.muted) midiOut.play("changeInstrument("++instrument++"),1_",note,duration);
}
var stageFromRadius=function(radius){
if(radius>235) return 1;
if(radius>175) return 2;
if(radius>112) return 3;
return 4;
}
var bubbleRadius=function(stage,kind){
var radius=VERSION_SIZES[math.clamp(stage,1,4)];
if(kind=="hype") radius+=20;
elseif(kind=="leak") radius=29;
return radius;
}
var orbitPosition=function(radius,angle){
return CX+math.cos(angle)*radius,CY+math.sin(angle)*radius*ORBIT_Y;
}
var lineProjection=function(x,y){
var ox=x-LINE_X;var oy=y-LINE_Y;
var along=ox*LINE_DX+oy*LINE_DY;
var px=LINE_X+LINE_DX*along;var py=LINE_Y+LINE_DY*along;
return along,math.dist(x,y,px,py);
}
var kindTitle=function(kind){
select(kind){
case "hype" { return "HYPE 河豚"; }
case "jelly" { return "幻觉水母"; }
case "boot" { return "技术债旧靴子"; }
case "leak" { return "基准泄漏气泡"; }
}
return "模型鱼";
}
var pushLimited=function(array,item,limit){
table.push(array,item);
while(#array>limit) table.remove(array,1);
}
// -------------------- 实体与关卡 --------------------
var makeModel=function(index){
var data=levelData();
var def=modelDefs[(index-1)%#modelDefs+1];
var radius=278+((index-1)%3)*12+math.floor((index-1)/3)*5;
var angle=PHASES[(index-1)%#PHASES+1]+game.level*0.07;
var urgent=game.level==#levels && index==1;
//最终关预先埋下一个可救的小模型:HYPE 过线时二者会在同一射线上形成稳定连锁。
if(urgent){radius=142;angle=0.62;}
elseif(game.level==#levels && index==7) angle+=0.50; //让 HYPE 保持完整轮廓,不把外圈模型吞进肚子里。
game.nextEntityId++;
var x,y=orbitPosition(radius,angle);
return {
id=game.nextEntityId;kind="model";state="orbit";name=def.name;color=def.color;mark=def.mark;
radius=radius;angle=angle;spin=data.spin*(0.94+((index-1)%4)*0.035);direction=1;
stage=stageFromRadius(radius);r=bubbleRadius(stageFromRadius(radius),"model");x=x;y=y;
boosted=false;fallAngle=0;savedSlot=0;urgent=urgent
};
}
var makeSpecial=function(spec,index){
game.nextEntityId++;
var kind=spec.kind;
var radius=235;var angle=0.7+index*1.23;var spin=0.58;var hitRadius=34;
if(kind=="hype"){radius=262;angle=0.92+game.level*0.13;spin=0.55;}
elseif(kind=="jelly"){radius=205;angle=1.18+game.level*0.08;spin=-0.62;hitRadius=38;}
elseif(kind=="boot"){radius=158;angle=4.22+game.level*0.1;spin=0.53;hitRadius=36;}
elseif(kind=="leak"){radius=198;angle=5.05+game.level*0.07;spin=-0.50;hitRadius=31;}
var x,y=orbitPosition(radius,angle);
return {
id=game.nextEntityId;kind=kind;state="waiting";appearAt=spec.at;
radius=radius;angle=angle;spin=spin;stage=stageFromRadius(radius);
r=kind=="hype" ? bubbleRadius(stageFromRadius(radius),kind) : hitRadius;
x=x;y=y;wobble=0
};
}
var resetLevel=function(levelIndex){
//重开/切关时立即清掉尚未结束的事件音,绝不保留背景声。
if(midiOut) midiOut.reset();
game.level=math.clamp(levelIndex,1,#levels);
game.state=STATE_PLAY;game.elapsed=0;game.intro=game.level==1 ? 1.6 : 0;game.resultTime=0;
game.entities=[];game.particles=[];game.shards=[];game.shocks=[];game.splashes=[];game.feathers=[];
game.score=0;game.leaks=0;game.saved=0;game.shotId=0;game.chainCount=0;game.chainTime=0;
game.cooldown=0;game.stun=0;game.strike=null;game.neckWobble=0;game.screenShake=0;
game.status="";game.statusTime=0;game.winDelay=0;game.nextEntityId=0;game.lineReady=false;
game.gagText="";game.gagTime=0;game.gagMax=0;game.finalCue=0;
game.mega=null;game.megaShotId=-1;game.hypeShotId=-1;game.pelicanBlast=0;game.flash=0;
var data=levelData();
for(i=1;data.fish) table.push(game.entities,makeModel(i));
for(i,spec in data.specials) table.push(game.entities,makeSpecial(spec,i));
sceneDirty=true;
}
var activeModelCount=function(){
var count=0;
for(i,e in game.entities) if(e.kind=="model" && e.state=="orbit") count++;
return count;
}
var checkClear=function(){
if(game.state==STATE_PLAY && activeModelCount()==0 && game.winDelay<=0) game.winDelay=0.82;
}
// -------------------- 短寿命反馈 --------------------
var spawnDots=function(x,y,color,count,speed,size){
for(i=1;count){
var angle=math.random()*math.pi*2;
var velocity=speed*(0.35+math.random()*0.65);
pushLimited(game.particles,{
x=x;y=y;vx=math.cos(angle)*velocity;vy=math.sin(angle)*velocity;
life=0.38+math.random()*0.38;maxLife=0.76;size=size*(0.55+math.random()*0.75);
color=color;gravity=80+math.random()*140
},260);
}
}
var spawnVersionShards=function(text,x,y,color){
var chars=string.split(text);
for(i,ch in chars){
pushLimited(game.shards,{
text=ch;x=x+(i-(#chars+1)/2)*7;y=y;vx=(i-(#chars+1)/2)*32+math.random(-18,18);
vy=-95-math.random()*50;life=0.72;maxLife=0.72;color=color;spin=math.random(-160,160);angle=0
},60);
}
}
var spawnSplash=function(x,color){
pushLimited(game.splashes,{x=x;y=654;life=0.55;maxLife=0.55;color=color},24);
for(i=1;7){
pushLimited(game.particles,{
x=x;y=654;vx=math.random(-70,70);vy=math.random(-180,-65);
life=0.48+math.random()*0.25;maxLife=0.72;size=2+math.random()*2.3;
color=0xFF66DDFC;gravity=360
},260);
}
}
var spawnFeathers=function(x,y,count){
for(i=1;count){
pushLimited(game.feathers,{
x=x+math.random(-28,28);y=y+math.random(-34,10);
vx=math.random(-150,125);vy=math.random(-245,-105);
angle=math.random()*360;spin=math.random(-260,260);
life=0.85+math.random()*0.55;maxLife=1.4;size=8+math.random()*6
},22);
}
}
var triggerMegaChain=function(x,y){
if(game.megaShotId==game.shotId) return;
game.megaShotId=game.shotId;
game.mega={x=x;y=y;life=1.05;maxLife=1.05};
game.pelicanBlast=1.18;game.flash=1.15;
game.screenShake=math.max(game.screenShake,3.2);
game.cooldown=math.max(game.cooldown,0.86);
spawnFeathers(135,610,10);
setGag(game.level==#levels ? "大的真来了!" : "这动静不对!",1.08,0xFFFFE98A);
setStatus("一嘴核爆级连锁——鹈鹕当场惊跌坐!",1.4);
if(game.level==#levels) game.finalCue=3;
playNote(47,43,145);
}
var burstEntity=function(entity,depth,shotId){
if(!entity || entity.state!="orbit") return false;
var x=entity.x;var y=entity.y;var stage=entity.stage : 1;
var color=entity.kind=="leak" ? 0xFF62F4D4 : (entity.color : VERSION_COLORS[stage]);
entity.state=entity.kind=="model" ? "falling" : "gone";
var shockMax=70+stage*5;
if(entity.kind=="hype") shockMax=168;
elseif(entity.kind=="leak") shockMax=52;
table.push(game.shocks,{x=x;y=y;r=4;max=shockMax;age=0;delay=depth*0.045;duration=0.34;depth=depth;source=entity.id;shotId=shotId;hit={}});
spawnDots(x,y,color,entity.kind=="hype" ? 30 : 15,entity.kind=="hype" ? 245 : 165,entity.kind=="hype" ? 5 : 3.6);
if(entity.kind=="model"){
spawnVersionShards(VERSION_LABELS[stage],x,y-8,VERSION_COLORS[stage]);
entity.vx=(x-CX)*0.18+math.random(-65,65);
entity.vy=-105-math.random()*65;
entity.fallAngle=math.random(-25,25);
game.saved++;
game.score+=100*stage+depth*45;
}
elseif(entity.kind=="hype"){
spawnVersionShards("HYPE",x,y-6,0xFFFFD65B);
game.score+=500;game.hypeShotId=shotId;
setStatus("HYPE 爆开:超大范围连锁冲击!",1.15);
}
elseif(entity.kind=="leak"){
spawnVersionShards("LEAK",x,y-5,0xFF62F4D4);
game.score+=280;
setStatus("基准泄漏已封堵,附近版本恢复常速",1.15);
}
if(shotId==game.shotId){
game.chainCount++;
game.chainTime=1.0;
//普通四连或 HYPE 带出的任意连锁,都会进入一次短促的招牌爆发镜头。
if(game.chainCount>=4 || (game.chainCount>=2 && game.hypeShotId==shotId)) triggerMegaChain(x,y);
}
game.screenShake=math.max(game.screenShake,entity.kind=="hype" ? 1 : 0.42);
playNote(depth>=2 ? 115 : 114,60+math.min(depth,5)*4+(stage-1)*2,70+depth*12);
checkClear();
return true;
}
var captureModel=function(entity){
if(entity.state!="orbit") return;
entity.state="captured";entity.captureAge=0;
game.leaks++;
game.screenShake=1;
spawnDots(entity.x,entity.y,0xFFFF6FAD,22,175,4);
playNote(55,42,210);
if(!RELAXED_AGI_MODE || game.leaks>=3){
game.state=STATE_FAILED;game.resultTime=0;game.strike=null;
setStatus("发布搞错了:把炼废版上传了!",2);
setGag("上传错了!",1.15,0xFFFF7FAB);
playNote(13,48,150);
}
else{
var letter=(['A','G','I'])[game.leaks];
setStatus((game.leaks==1 ? "炼废了!" : "又炼废了!")++" "++letter++" 已点亮",1.35);
checkClear();
}
}
// -------------------- 测试线命中 --------------------
var findFirstLineHit=function(){
var found;var best=100000;var bestPerp;
for(i,e in game.entities){
if(e.state=="orbit"){
var hitRadius=e.r;
var along,perp=lineProjection(e.x,e.y);
if(along>=0 && along<=LINE_LEN && perp<=hitRadius+2 && along<best){
found=e;best=along;bestPerp=perp;
}
}
}
return found,best,bestPerp;
}
var beginStrike=function(){
if(game.state==STATE_WIN){
resetLevel(game.level==#levels ? 1 : game.level+1);
return;
}
if(game.state==STATE_FAILED){
resetLevel(game.level);
return;
}
if(game.state!=STATE_PLAY || game.cooldown>0 || game.stun>0) return;
game.shotId++;
game.chainCount=0;game.chainTime=0;
var hit,along=findFirstLineHit();
var strikeLength=hit ? math.clamp(along,115,LINE_LEN) : LINE_LEN;
game.strike={age=0;target=strikeLength;length=72;hit=hit ? hit.kind : "miss"};
game.cooldown=0.34;game.neckWobble=1;
if(!hit){
setStatus("落空——别追泡泡,等它自己穿过 TEST LINE",0.9);
spawnDots(LINE_END_X,LINE_END_Y,0xFF7FCBE5,7,80,2.4);
playNote(73,48,65);
return;
}
if(hit.kind=="model" || hit.kind=="hype" || hit.kind=="leak"){
burstEntity(hit,0,game.shotId);
}
elseif(hit.kind=="jelly"){
hit.state="gone";
setStatus("戳破幻觉:看起来很强的结果当场蒸发",1.05);
setGag("过拟合到出现幻觉",0.82,0xFFDAB9FF);
spawnDots(hit.x,hit.y,0xFFB98CFF,18,145,3.4);
spawnVersionShards("幻觉",hit.x,hit.y,0xFFD5C3FF);
playNote(10,69,90);
}
elseif(hit.kind=="boot"){
hit.state="gone";game.stun=0.82;
setStatus("技术债被一嘴撞飞——长嘴仍麻 0.8 秒",1.15);
setGag("技术债反弹!",0.76,0xFFFFC778);
spawnDots(hit.x,hit.y,0xFFFFB55E,22,175,3.7);
spawnVersionShards("债",hit.x,hit.y,0xFFFFC46E);
playNote(115,48,95);
}
}
// -------------------- 每帧更新 --------------------
var updateParticles=function(dt){
for(i=#game.particles;1;-1){
var p=game.particles[i];
p.life-=dt;
if(p.life<=0) table.remove(game.particles,i);
else{
p.vy+=p.gravity*dt;p.x+=p.vx*dt;p.y+=p.vy*dt;
p.vx*=math.max(0,1-dt*1.7);
}
}
for(i=#game.shards;1;-1){
var s=game.shards[i];s.life-=dt;
if(s.life<=0) table.remove(game.shards,i);
else{s.vy+=240*dt;s.x+=s.vx*dt;s.y+=s.vy*dt;s.angle+=s.spin*dt;}
}
for(i=#game.splashes;1;-1){
game.splashes[i].life-=dt;
if(game.splashes[i].life<=0) table.remove(game.splashes,i);
}
for(i=#game.feathers;1;-1){
var f=game.feathers[i];f.life-=dt;
if(f.life<=0) table.remove(game.feathers,i);
else{
f.vy+=255*dt;f.x+=f.vx*dt;f.y+=f.vy*dt;f.angle+=f.spin*dt;
f.vx*=math.max(0,1-dt*0.9);
}
}
}
var updateFalling=function(dt){
for(i,e in game.entities){
if(e.state=="falling"){
e.vy+=520*dt;e.x+=e.vx*dt;e.y+=e.vy*dt;e.fallAngle+=170*dt;
e.vx*=math.max(0,1-dt*0.65);
if(e.y>=657){
e.state="saved";e.savedSlot=game.saved;e.y=672;e.x=math.clamp(e.x,335,1010);
spawnSplash(e.x,e.color);
playNote(74,52+(e.savedSlot%5)*2,70);
}
}
elseif(e.state=="captured"){
e.captureAge+=dt;
var t=math.clamp(e.captureAge/0.42,0,1);
e.x=math.lerp(e.x,CX,t*0.18);e.y=math.lerp(e.y,CY,t*0.18);
if(t>=1) e.state="gone";
}
}
}
var updateStrike=function(dt){
if(!game.strike) return;
var strike=game.strike;
strike.age+=dt;
if(strike.age<0.065){
var t=strike.age/0.065;
strike.length=72+(strike.target-72)*(1-(1-t)*(1-t)*(1-t));
}
elseif(strike.age<0.125) strike.length=strike.target;
elseif(strike.age<0.34){
var t=(strike.age-0.125)/0.215;
strike.length=72+(strike.target-72)*(1-t)*(1-t);
}
else game.strike=null;
}
var updateShocks=function(dt){
for(i=#game.shocks;1;-1){
var shock=game.shocks[i];shock.age+=dt;
var activeAge=shock.age-shock.delay;
if(activeAge>=0){
var t=math.clamp(activeAge/shock.duration,0,1);
shock.r=shock.max*(1-(1-t)*(1-t));
//depth < 0 仅用于版本升级的装饰环,绝不能误触发连锁爆破。
if(shock.depth>=0){
for(j,e in game.entities){
if(e.state=="orbit" && e.id!=shock.source && !shock.hit[e.id]
&& (e.kind=="model" || e.kind=="hype" || e.kind=="leak") ){
if(math.dist(shock.x,shock.y,e.x,e.y)<=shock.r+e.r){
shock.hit[e.id]=true;
burstEntity(e,shock.depth+1,shock.shotId);
}
}
}
}
}
if(activeAge>shock.duration) table.remove(game.shocks,i);
}
}
var activateSpecials=function(){
for(i,e in game.entities){
if(e.state=="waiting" && game.elapsed>=e.appearAt){
e.state="orbit";
setStatus(kindTitle(e.kind)++" 进入本轮测试",1.05);
spawnDots(e.x,e.y,e.kind=="boot" ? 0xFFFFB05C : 0xFF90E8FF,12,105,3);
if(e.kind=="hype"){
game.hypeSeen++;
if(game.level==#levels){
setGag("大的要来了……",1.02,0xFFFFE589);game.finalCue=1;
}
else setGag(game.hypeSeen==1 ? "大的要来了……" : "大的又要来了!",0.92,0xFFFFE589);
}
//自动入场保持安静,音效只服务玩家操作和明确结果。
}
}
}
var updateOrbiting=function(dt){
//先更新行业现象,使 LEAK 的位置用于同一帧加速检测。
for(i,e in game.entities){
if(e.state=="orbit" && e.kind!="model" && e.kind!="hype"){
e.angle+=e.spin*dt;
e.x,e.y=orbitPosition(e.radius,e.angle);
e.wobble=math.max(0,e.wobble-dt*3.4);
}
}
var leakEntity;
for(i,e in game.entities) if(e.kind=="leak" && e.state=="orbit") leakEntity=e;
var data=levelData();
for(i,e in game.entities){
if(e.state=="orbit" && (e.kind=="model" || e.kind=="hype")){
e.boosted=false;
var boost=1;
if(e.kind=="model" && leakEntity && math.dist(e.x,e.y,leakEntity.x,leakEntity.y)<175){
boost=2.55;e.boosted=true;
}
var oldStage=e.stage;
e.stage=stageFromRadius(e.radius);
var versionSpeed=1+(e.stage-1)*0.17;
var inward=data.inward*(e.kind=="hype" ? 0.72 : 1)*(1+(e.stage-1)*0.12)*boost;
e.radius-=inward*dt;
e.angle+=e.spin*versionSpeed*boost*dt;
e.x,e.y=orbitPosition(e.radius,e.angle);
e.r=bubbleRadius(e.stage,e.kind);
var newStage=stageFromRadius(e.radius);
if(newStage>oldStage){
e.stage=newStage;e.r=bubbleRadius(newStage,e.kind);
spawnDots(e.x,e.y,VERSION_COLORS[newStage],10,95,2.8);
pushLimited(game.shocks,{x=e.x;y=e.y;r=3;max=e.r+17;age=0;delay=0;duration=0.28;depth=-99;source=e.id;shotId=-1;hit={}},40);
if(e.kind=="model") setStatus(e.name++" 升级至 "++VERSION_LABELS[newStage],0.78);
}
if(e.radius<=CAPTURE_RADIUS){
if(e.kind=="model") captureModel(e);
else e.state="gone";
}
}
}
}
var updateStoryCues=function(){
if(game.level==#levels && game.finalCue==1){
for(i,e in game.entities){
if(e.kind=="model" && e.state=="orbit" && e.urgent && e.radius<120){
setGag("小的要去了!",0.92,0xFFFF91BE);game.finalCue=2;
break;
}
}
}
}
var updateGame=function(dt){
game.elapsed+=dt;
activateSpecials();
updateOrbiting(dt);
updateStoryCues();
updateShocks(dt);
checkClear();
if(game.winDelay>0){
game.winDelay-=dt;
if(game.winDelay<=0 && game.state==STATE_PLAY){
game.state=STATE_WIN;game.resultTime=0;game.strike=null;
setStatus("全部返回训练池——今天仍未 AGI 。",2);
playNote(14,76,180);
}
}
}
// -------------------- 静态场景缓存 --------------------
var buildSceneCache=function(){
if(sceneCache) sceneCache.delete();
var width=math.floor(CANVAS_W*CACHE_SCALE);
var height=math.floor(CANVAS_H*CACHE_SCALE);
sceneCache=gdip.bitmap(width,height);
var graphics=gdip.graphics(sceneCache);
graphics.scale(CACHE_SCALE,CACHE_SCALE);
graphics.smoothingMode=4/*_SmoothingModeAntiAlias*/;
graphics.textRenderingHint=4/*_TextRenderingHintAntiAlias*/;
var bg=gdip.lineBrush(::POINTF(0,0),::POINTF(CANVAS_W,CANVAS_H),0xFF102D42,0xFF070A18);
graphics.fillRect(bg,0,0,CANVAS_W,CANVAS_H);bg.delete();
var haze=gdip.solidBrush(0x261FA3B8);
graphics.fillEllipse(haze,270,-160,760,650);haze.delete();
for(i,s in stars){
var brush=gdip.solidBrush(alphaColor(0xFFD8F5FF,s.alpha));
graphics.fillCircle(brush,s.x,s.y,s.size);brush.delete();
}
var top=gdip.solidBrush(0x7A06111F);
graphics.fillRect(top,0,0,CANVAS_W,92);top.delete();
drawText(graphics,"鹈 鹕 之 门",FONT_24B,26,8,280,38,0xFFF3FBFF,0);
drawText(graphics,"PELICAN GATE · AGI BENCHMARK CONTROL",FONT_10,28,45,360,18,0x9BC3E8F4,0);
drawText(graphics,"目标经过 TEST LINE 时点击任意位置 · 越晚越容易连爆,也越接近 AGI",FONT_13,28,68,720,20,0xD7D6F4FA,0);
var data=levelData();
drawText(graphics,"第 "++game.level++" / "++#levels++" 关",FONT_11,790,15,120,22,0xAFC9DDE8,0);
drawText(graphics,data.name,FONT_18B,790,36,270,30,data.accent,0);
drawText(graphics,data.subtitle,FONT_13,790,68,300,20,0xBFD8E7EE,0);
//升级环:与模型鱼实际使用的椭圆轨道完全一致。
var ringRadii=[300,235,175,112,64];
for(i,r in ringRadii){
var alpha=i==#ringRadii ? 92 : 42+i*7;
var pen=gdip.pen(alphaColor(data.accent,alpha),i==#ringRadii ? 2 : 1);
graphics.drawEllipse(pen,CX-r,CY-r*ORBIT_Y,r*2,r*2*ORBIT_Y);pen.delete();
}
var radial=gdip.pen(0x173AD0E7,1);
for(i=0;11){
var a=i*math.pi/6;
graphics.drawLine(radial,CX+math.cos(a)*66,CY+math.sin(a)*66*ORBIT_Y,CX+math.cos(a)*302,CY+math.sin(a)*302*ORBIT_Y);
}
radial.delete();
//把版本说明移到左侧信息区,避免任何静态标签盖住动态泡泡。
drawText(graphics,"VERSION PATH",FONT_10,26,188,100,17,0x8397C9D8,0);
drawText(graphics,"1.2 › 2.5 › 3.0 › AGI?",FONT_12,26,205,248,22,0xCDE5F6FA,0);
//淡淡但清楚的基准测试线由底层辉光和短线段组成;点击位置不参与瞄准。
var lineGlow=gdip.pen(0x3576E8FF,8);
graphics.drawLine(lineGlow,LINE_X,LINE_Y,LINE_END_X,LINE_END_Y);lineGlow.delete();
for(distance=8;distance<LINE_LEN;distance+=24){
var a=math.min(190,95+distance*0.12);
var pen=gdip.pen(alphaColor(0xFF76E8FF,a),2);
graphics.drawLine(pen,LINE_X+LINE_DX*distance,LINE_Y+LINE_DY*distance,
LINE_X+LINE_DX*(distance+13),LINE_Y+LINE_DY*(distance+13));
pen.delete();
}
drawText(graphics,"BENCHMARK TEST LINE",FONT_10,246,524,210,18,0xA85ECFE7,0);
//训练池位于前景底部,所有被释放的普通模型鱼都落回这里。
var poolShadow=gdip.solidBrush(0x66000000);
graphics.fillRoundRect(poolShadow,292,630,744,80,26);poolShadow.delete();
var pool=gdip.lineBrush(::POINTF(300,636),::POINTF(1018,704),0xC515617A,0xEA082A48);
graphics.fillRoundRect(pool,300,632,728,76,24);pool.delete();
var poolEdge=gdip.pen(0xB45CE8FF,2);
graphics.drawArc(poolEdge,312,622,704,38,184,172);poolEdge.delete();
drawText(graphics,"T R A I N I N G",FONT_14B,685,674,250,24,0x836BE5F7,1);
drawText(graphics,"模型鱼返回训练池",FONT_12,838,651,170,17,0x7CCBEAF2,1);
graphics.delete();sceneDirty=false;
}
// -------------------- 动态绘制 --------------------
var drawVortex=function(graphics){
var failed=game.state==STATE_FAILED;
var baseColor=failed ? 0xFFFF4A8E : levelData().accent;
var pulse=math.sin(game.pulse/125);
if(failed){
var spot=gdip.solidBrush(0x24FF5C9A);
graphics.fillPolygon(spot,[[430,92],[520,92],[CX+34,CY+12],[CX-24,CY+10]]);
graphics.fillPolygon(spot,[[760,92],[850,92],[CX+26,CY+14],[CX-20,CY+8]]);spot.delete();
}
for(i=5;1;-1){
var radius=28+i*12+3*pulse;
var glow=gdip.solidBrush(alphaColor(baseColor,8+i*5));
graphics.fillCircle(glow,CX,CY,radius);glow.delete();
}
for(i=1;4){
var r=24+i*11;
var pen=gdip.pen(alphaColor(baseColor,105+i*24),1.2+i*0.65);
var start=(i%2 ? 1 : -1)*game.pulse/(8+i*2)+i*41;
graphics.drawArc(pen,CX-r,CY-r,r*2,r*2,start,205+i*18);pen.delete();
}
var core=gdip.solidBrush(failed ? 0xFF3B061C : 0xFF050613);
graphics.fillCircle(core,CX,CY,24+2*pulse);core.delete();
var dot=gdip.solidBrush(alphaColor(0xFFFFFFFF,170+60*pulse));
graphics.fillCircle(dot,CX-5,CY-5,4);dot.delete();
drawText(graphics,"AGI?",FONT_14B,CX-38,CY-13,76,26,failed ? 0xFFFFD4E4 : 0xFFEAFBFF,1);
}
var drawActiveLine=function(graphics){
if(!game.lineReady || game.state!=STATE_PLAY) return;
var hit,along=findFirstLineHit();
if(!hit) return;
var alpha=135+75*math.sin(game.pulse/52);
var glow=gdip.pen(alphaColor(0xFF8CFAFF,alpha*0.28),10);
var core=gdip.pen(alphaColor(0xFFDFFFFF,alpha),2.4);
var endX=LINE_X+LINE_DX*along;var endY=LINE_Y+LINE_DY*along;
graphics.drawLine(glow,LINE_X,LINE_Y,endX,endY);
graphics.drawLine(core,LINE_X,LINE_Y,endX,endY);
graphics.drawCircle(core,endX,endY,hit.r+5+2*math.sin(game.pulse/55));
core.delete();glow.delete();
}
var drawPoolWater=function(graphics){
var pen=gdip.pen(0x6969E9FF,1.5);
if(game.mega){
//爆发波纹留在训练池后方,避免圆环压过水面与 TRAINING 字样。
var cover=gdip.solidBrush(0xF0082A48);graphics.fillRoundRect(cover,300,632,728,76,24);cover.delete();
}
var offset=(game.pulse/18)%42;
for(x=310-offset;x<1020;x+=42){
graphics.drawArc(pen,x,641,34,11,190,150);
}
pen.delete();
var shine=gdip.pen(0x3267F4FF,5);
graphics.drawArc(shine,315,625,697,36,188,164);shine.delete();
}
var drawFishShape=function(graphics,color,mark,scale,overfit){
var body=gdip.solidBrush(color);
var dark=gdip.solidBrush(shadeColor(color,-65));
var light=gdip.solidBrush(shadeColor(color,40));
graphics.fillPolygon(dark,[[-17*scale,0],[-29*scale,-10*scale],[-27*scale,10*scale]]);
if(overfit){
//同一条鱼长出过多装饰鳍:不增加新实体,也能一眼看出“训练集卷满了”。
graphics.fillPolygon(light,[[-13*scale,-7*scale],[-11*scale,-20*scale],[-4*scale,-8*scale]]);
graphics.fillPolygon(light,[[0,-8*scale],[4*scale,-22*scale],[9*scale,-7*scale]]);
graphics.fillPolygon(light,[[7*scale,7*scale],[13*scale,18*scale],[14*scale,5*scale]]);
}
graphics.fillEllipse(body,-18*scale,-10*scale,36*scale,20*scale);
graphics.fillPolygon(light,[[-4*scale,-7*scale],[5*scale,-17*scale],[10*scale,-6*scale]]);
if(mark%3==1) graphics.fillCircle(light,-2*scale,1*scale,3.3*scale);
elseif(mark%3==2) graphics.fillRect(light,-7*scale,-2*scale,12*scale,4*scale);
else graphics.fillPolygon(light,[[-8*scale,6*scale],[0,0],[8*scale,7*scale]]);
if(overfit){
var medal=gdip.solidBrush(0xFFFFD45B);
graphics.fillCircle(medal,-3*scale,2*scale,3.2*scale);medal.delete();
}
var eyeWhite=gdip.solidBrush(0xFFF7FFFF);var pupil=gdip.solidBrush(0xFF07131E);
graphics.fillCircle(eyeWhite,10*scale,-3*scale,3.6*scale);
graphics.fillCircle(pupil,11*scale,-3*scale,1.7*scale);
pupil.delete();eyeWhite.delete();light.delete();dark.delete();body.delete();
}
var entityLabelClear=function(entity){
for(i,other in game.entities){
if(other.id!=entity.id && other.state=="orbit" && math.dist(entity.x,entity.y,other.x,other.y)<entity.r+other.r+42) return false;
}
return true;
}
var drawModelBubble=function(graphics,e){
var stage=e.stage;var radius=e.r;var color=VERSION_COLORS[stage];
var charred=stage==4 && e.radius<88;
if(e.boosted){
var boost=gdip.pen(alphaColor(0xFF5DFFD4,115+60*math.sin(game.pulse/80)),5);
graphics.drawCircle(boost,e.x,e.y,radius+8);boost.delete();
}
if(e.urgent){
var warning=gdip.pen(alphaColor(0xFFFF76A9,135+80*math.sin(game.pulse/55)),3);
graphics.drawArc(warning,e.x-radius-10,e.y-radius-10,(radius+10)*2,(radius+10)*2,205,58);
graphics.drawArc(warning,e.x-radius-10,e.y-radius-10,(radius+10)*2,(radius+10)*2,25,58);warning.delete();
}
var glow=gdip.pen(alphaColor(color,42+stage*11),8+stage*2);
var outline=gdip.pen(alphaColor(color,205),1.7+stage*0.25);
var fill=gdip.solidBrush(alphaColor(color,30+stage*7));
graphics.fillCircle(fill,e.x,e.y,radius);
graphics.drawCircle(glow,e.x,e.y,radius+1);
graphics.drawCircle(outline,e.x,e.y,radius);
fill.delete();outline.delete();glow.delete();
var highlight=gdip.pen(0xB8FFFFFF,2.3);
graphics.drawArc(highlight,e.x-radius+5,e.y-radius+5,(radius-5)*2,(radius-5)*2,205,72);highlight.delete();
if(charred){
for(i=0;2){
var smoke=gdip.solidBrush(alphaColor(0xFF8CA0A8,90-i*20));
graphics.fillCircle(smoke,e.x-9+i*9+math.sin(game.pulse/120+i)*4,e.y-radius-8-i*8,7-i);smoke.delete();
}
}
var tangentX=-math.sin(e.angle);
var tangentY=math.cos(e.angle)*ORBIT_Y;
var angle=math.deg(math.atan2(tangentY,tangentX));
var saved=graphics.save();
graphics.translate(e.x,e.y+5);
graphics.rotate(angle);
drawFishShape(graphics,charred ? shadeColor(e.color,-95) : e.color,e.mark,0.72+stage*0.08,stage==4);
graphics.restore(saved);
drawText(graphics,VERSION_LABELS[stage],stage==4 ? FONT_12B : FONT_12,e.x-radius,e.y-radius+3,radius*2,20,0xF7FFFFFF,1);
if(stage==4) drawText(graphics,charred ? "炼废中" : "训练集 100%",FONT_10,e.x-radius,e.y+radius-20,radius*2,16,charred ? 0xFFFFA2A2 : 0xFFFFE7A0,1);
if(entityLabelClear(e)) drawText(graphics,e.name,FONT_10,e.x-radius-8,e.y+radius+9,radius*2+16,17,alphaColor(e.color,215),1);
}
var drawHype=function(graphics,e){
var r=e.r;var pulse=2*math.sin(game.pulse/85);
var fill=gdip.solidBrush(0x42FFD34F);var glow=gdip.pen(0x85FFD95F,11+pulse);var edge=gdip.pen(0xEFFFF1A3,2.3);
graphics.fillCircle(fill,e.x,e.y,r);graphics.drawCircle(glow,e.x,e.y,r+2);graphics.drawCircle(edge,e.x,e.y,r);
edge.delete();glow.delete();fill.delete();
var puffer=gdip.solidBrush(0xFFFFC94C);var dark=gdip.solidBrush(0xFF9C5D23);
for(i=0;11){
var a=i*math.pi/6;
var x1=e.x+math.cos(a)*20;var y1=e.y+math.sin(a)*20;
graphics.fillPolygon(puffer,[[x1+math.cos(a-0.22)*8,y1+math.sin(a-0.22)*8],[e.x+math.cos(a)*29,e.y+math.sin(a)*29],[x1+math.cos(a+0.22)*8,y1+math.sin(a+0.22)*8]]);
}
graphics.fillCircle(puffer,e.x,e.y,22);
graphics.fillCircle(dark,e.x+8,e.y-5,2.4);graphics.fillCircle(dark,e.x-7,e.y-5,2.4);
dark.delete();puffer.delete();
drawText(graphics,"HYPE",FONT_12B,e.x-r,e.y+7,r*2,22,0xFF5E3515,1);
drawText(graphics,"连锁",FONT_11,e.x-r,e.y+26,r*2,17,0xFF321B08,1);
}
var drawJelly=function(graphics,e){
var wobble=e.wobble*6+math.sin(game.pulse/120+e.id)*2;
var glow=gdip.pen(0x527E9CFF,10);var edge=gdip.pen(0xC5C6B2FF,2);
var fill=gdip.solidBrush(0x4F9A80FF);
graphics.fillPie(fill,e.x-31,e.y-25,62,50,180,180);
graphics.drawArc(glow,e.x-33,e.y-27,66,54,180,180);
graphics.drawArc(edge,e.x-31,e.y-25,62,50,180,180);
var tentacle=gdip.pen(0x9DB8A5FF,2.2);
for(i=-2;2){
graphics.drawBezier(tentacle,e.x+i*10,e.y,e.x+i*12+wobble,e.y+13,e.x+i*5-wobble,e.y+21,e.x+i*9,e.y+33);
}
tentacle.delete();fill.delete();edge.delete();glow.delete();
drawText(graphics,"幻觉",FONT_11,e.x-31,e.y-20,62,20,0xE9F0E9FF,1);
}
var drawBoot=function(graphics,e){
var shake=e.wobble*math.sin(game.pulse/18)*5;
var saved=graphics.save();graphics.translate(e.x+shake,e.y);graphics.rotate(-12+e.wobble*9);
var glow=gdip.pen(0x4BFF9E50,10);var edge=gdip.pen(0xE8D79A5B,2);
var leather=gdip.solidBrush(0xFF70401F);var sole=gdip.solidBrush(0xFF281B16);
var points=[[-18,-28],[9,-28],[7,4],[20,14],[34,17],[32,28],[-11,28],[-20,17]];
graphics.drawPolygon(glow,points);graphics.fillPolygon(leather,points);graphics.drawPolygon(edge,points);
graphics.fillRoundRect(sole,-15,22,49,9,4);
var patch=gdip.pen(0xFFE6B06C,1.4);graphics.drawLine(patch,-9,-12,5,-4);graphics.drawLine(patch,-9,-5,5,3);
patch.delete();sole.delete();leather.delete();edge.delete();glow.delete();graphics.restore(saved);
drawText(graphics,"技术债",FONT_10,e.x-34,e.y+31,68,17,0xEFD9A15E,1);
}
var drawLeak=function(graphics,e){
var r=e.r;var pulse=2*math.sin(game.pulse/75);
var glow=gdip.pen(0x654CFFD2,9+pulse);var fill=gdip.solidBrush(0x3B3BFFD0);var edge=gdip.pen(0xDD91FFE5,2);
graphics.fillCircle(fill,e.x,e.y,r);graphics.drawCircle(glow,e.x,e.y,r+1);graphics.drawCircle(edge,e.x,e.y,r);
var crack=gdip.pen(0xF0E9FFFF,2);
graphics.drawLines(crack,[[e.x-5,e.y-r+7],[e.x+2,e.y-8],[e.x-4,e.y+2],[e.x+7,e.y+11],[e.x+2,e.y+r-7]]);
crack.delete();edge.delete();fill.delete();glow.delete();
drawText(graphics,"LEAK",FONT_11,e.x-r,e.y-9,r*2,18,0xFFF0FFFF,1);
}
var drawEntities=function(graphics){
for(i,e in game.entities){
if(e.state=="orbit"){
if(e.kind=="model") drawModelBubble(graphics,e);
elseif(e.kind=="hype") drawHype(graphics,e);
elseif(e.kind=="jelly") drawJelly(graphics,e);
elseif(e.kind=="boot") drawBoot(graphics,e);
elseif(e.kind=="leak") drawLeak(graphics,e);
}
elseif(e.state=="falling" || e.state=="captured"){
var saved=graphics.save();graphics.translate(e.x,e.y);graphics.rotate(e.fallAngle : 0);
drawFishShape(graphics,e.color,e.mark,0.92);graphics.restore(saved);
}
elseif(e.state=="saved"){
var swimX=e.x+math.sin(game.pulse/420+e.id)*14;
var swimY=672+math.sin(game.pulse/260+e.id*2)*4;
var saved=graphics.save();graphics.translate(swimX,swimY);drawFishShape(graphics,e.color,e.mark,0.68);graphics.restore(saved);
}
}
}
var drawEffects=function(graphics){
for(i,shock in game.shocks){
if(shock.age>=shock.delay && shock.depth>=0){
var t=math.clamp((shock.age-shock.delay)/shock.duration,0,1);
var pen=gdip.pen(alphaColor(shock.depth==0 ? 0xFFFFFFFF : 0xFFFFD86B,210*(1-t)),2.2+3*(1-t));
graphics.drawCircle(pen,shock.x,shock.y,shock.r);pen.delete();
}
}
for(i,p in game.particles){
var alpha=255*math.clamp(p.life/p.maxLife,0,1);
var brush=gdip.solidBrush(alphaColor(p.color,alpha));
graphics.fillCircle(brush,p.x,p.y,p.size*(0.5+0.5*p.life/p.maxLife));brush.delete();
}
for(i,s in game.shards){
var alpha=255*math.clamp(s.life/s.maxLife,0,1);
drawText(graphics,s.text,FONT_12B,s.x-12,s.y-10,24,20,alphaColor(s.color,alpha),1);
}
for(i,s in game.splashes){
var t=1-s.life/s.maxLife;
var pen=gdip.pen(alphaColor(s.color,180*(1-t)),2.2);
graphics.drawArc(pen,s.x-10-t*28,s.y-5-t*6,20+t*56,10+t*13,195,150);pen.delete();
}
for(i,f in game.feathers){
var saved=graphics.save();graphics.translate(f.x,f.y);graphics.rotate(f.angle);
var alpha=230*math.clamp(f.life/f.maxLife,0,1);
var brush=gdip.solidBrush(alphaColor(0xFFF4F1E8,alpha));
var outline=gdip.pen(alphaColor(0xFF526873,alpha),1.2);
var shaft=gdip.pen(alphaColor(0xFF9DB0B9,alpha),1.2);
graphics.fillEllipse(brush,-f.size,-f.size*0.34,f.size*2,f.size*0.68);
graphics.drawEllipse(outline,-f.size,-f.size*0.34,f.size*2,f.size*0.68);
graphics.drawLine(shaft,-f.size*0.8,0,f.size*0.9,0);
shaft.delete();outline.delete();brush.delete();graphics.restore(saved);
}
}
var pelicanMood=function(){
var minRadius=999;var hasHype=false;var closePairs=0;
for(i=1;#game.entities){
var a=game.entities[i];
if(a.state=="orbit" && a.kind=="hype") hasHype=true;
if(a.state=="orbit" && a.kind=="model"){
minRadius=math.min(minRadius,a.radius);
for(j=i+1;#game.entities){
var b=game.entities[j];
if(b.state=="orbit" && b.kind=="model" && math.dist(a.x,a.y,b.x,b.y)<a.r+b.r+72) closePairs++;
}
}
}
return hasHype || closePairs>=2,minRadius<112;
}
var drawPelican=function(graphics){
var drool,panic=pelicanMood();
var blasted=game.pelicanBlast>0;
var poseSaved=graphics.save();
if(blasted){
var age=1-game.pelicanBlast/1.18;
var pose=age<0.16 ? age/0.16 : (age<0.78 ? 1 : math.max(0,(1-age)/0.22));
graphics.translate(130,640);graphics.rotate(-24*pose);graphics.translate(-130,-640);
graphics.translate(-8*pose,14*pose);
}
var wobble=game.neckWobble*math.sin(game.pulse/32)*5;
var bodyShadow=gdip.solidBrush(0x55000000);
graphics.fillEllipse(bodyShadow,63,654,155,32);bodyShadow.delete();
var foot=gdip.solidBrush(0xFFFFA62B);
graphics.fillEllipse(foot,94,670,47,12);graphics.fillEllipse(foot,145,671,49,12);foot.delete();
var body=gdip.solidBrush(0xFFF5F1E8);var wing=gdip.solidBrush(0xFFD7E1E5);var outline=gdip.pen(0xFF243541,2.1);
graphics.fillEllipse(body,70,585,132,99);graphics.drawEllipse(outline,70,585,132,99);
graphics.fillEllipse(wing,83,613,83,48);
if(blasted) graphics.fillPolygon(wing,[[105,634],[54,566],[91,649],[133,645]]);
var feather=gdip.pen(0x8B8EA7B1,1.3);graphics.drawArc(feather,94,622,55,26,190,135);graphics.drawArc(feather,101,631,52,23,190,130);feather.delete();
var headX;var headY;var tipX;var tipY;
if(game.strike){
tipX=LINE_X+LINE_DX*game.strike.length;tipY=LINE_Y+LINE_DY*game.strike.length;
headX=tipX-LINE_DX*82;headY=tipY-LINE_DY*82;
var neckBack=gdip.pen(0xFF263944,27);var neck=gdip.pen(0xFFF5F1E8,21);
graphics.drawLine(neckBack,151,616,headX,headY);graphics.drawLine(neck,151,616,headX,headY);
neck.delete();neckBack.delete();
}
else{
headX=LINE_X-LINE_DX*62;headY=LINE_Y-LINE_DY*62+wobble;
tipX=LINE_X;tipY=LINE_Y+wobble;
var neckBack=gdip.pen(0xFF263944,29);var neck=gdip.pen(0xFFF5F1E8,23);
//大幅张开的反向双弯明确形成蓄力 S,而不是缩成一个圆环。
var points=[[145,620],[207+wobble,615],[130-wobble,558],[headX,headY]];
graphics.drawCurve(neckBack,points);graphics.drawCurve(neck,points);
neck.delete();neckBack.delete();
}
graphics.fillCircle(body,headX,headY,20);graphics.drawCircle(outline,headX,headY,20);
var beak=gdip.solidBrush(game.stun>0 ? 0xFFB8A06D : 0xFFFFB52E);
var pouch=gdip.solidBrush(game.stun>0 ? 0xFF8F7751 : 0xFFFF8B36);
var baseX=headX+LINE_DX*8;var baseY=headY+LINE_DY*8;
graphics.fillPolygon(beak,[[baseX+LINE_NX*7,baseY+LINE_NY*7],[tipX+LINE_NX*2,tipY+LINE_NY*2],[tipX-LINE_NX*2,tipY-LINE_NY*2],[baseX-LINE_NX*3,baseY-LINE_NY*3]]);
graphics.fillPolygon(pouch,[[baseX-LINE_NX*2,baseY-LINE_NY*2],[tipX-LINE_NX*2,tipY-LINE_NY*2],[baseX-LINE_NX*13,baseY-LINE_NY*13]]);
beak.delete();pouch.delete();
var eye=gdip.solidBrush(0xFF0A1720);var eyeWhite=gdip.solidBrush(0xFFFFFFFF);
var eyeRadius=blasted || panic ? 6.2 : 4.1;
graphics.fillCircle(eyeWhite,headX+LINE_NX*5+LINE_DX*6,headY+LINE_NY*5+LINE_DY*6,eyeRadius);
graphics.fillCircle(eye,headX+LINE_NX*5+LINE_DX*(blasted ? 5 : 7),headY+LINE_NY*5+LINE_DY*(blasted ? 5 : 7),blasted ? 2.8 : 2.1);
eye.delete();eyeWhite.delete();
if(drool && !game.strike && game.stun<=0 && !blasted){
var t=0.58;var droolX=baseX+(tipX-baseX)*t+LINE_NX*8;var droolY=baseY+(tipY-baseY)*t+LINE_NY*8;
var length=28+8*math.sin(game.pulse/105);
var droolPen=gdip.pen(0xFF54E9FF,4.4);var droolDrop=gdip.solidBrush(0xFF54E9FF);var droolLight=gdip.solidBrush(0xEFFFFFFF);
graphics.drawBezier(droolPen,droolX,droolY,droolX+4,droolY+9,droolX-4,droolY+length-7,droolX,droolY+length);
graphics.fillCircle(droolDrop,droolX,droolY+length+5,6.2);
graphics.fillCircle(droolLight,droolX-1.8,droolY+length+2.5,1.6);
graphics.fillCircle(droolDrop,droolX+9,droolY+length+17,3.6);
droolLight.delete();droolDrop.delete();droolPen.delete();
}
if(panic && !blasted){
var sweat=gdip.solidBrush(0xE178E9FF);
graphics.fillEllipse(sweat,headX-24,headY-23,7,12);graphics.fillCircle(sweat,headX-20.5,headY-10,3.2);sweat.delete();
}
if(blasted) drawText(graphics,"!",FONT_24B,headX-43,headY-56,30,38,0xFFFFE98A,1);
if(game.stun>0){
var lightning=gdip.pen(0xFFFFE96B,3);
for(i=0;2){
var ox=190+i*17;var oy=540-i*6;
graphics.drawLines(lightning,[[ox,oy],[ox+8,oy-12],[ox+2,oy-19],[ox+14,oy-32]]);
}
lightning.delete();
}
outline.delete();wing.delete();body.delete();
graphics.restore(poseSaved);
}
var drawCinemaEffects=function(graphics){
if(!game.mega) return;
var t=1-game.mega.life/game.mega.maxLife;
var size=420+t*280;
megaImageAttributes.setAlphaMatrix(math.max(0.08,1-t*0.92));
graphics.drawImageRect(megaSprite,game.mega.x-size/2,game.mega.y-size/2,size,size,megaImageAttributes);
if(game.flash>0){
var flashRing=gdip.pen(alphaColor(0xFFFFFFFF,175*math.min(1,game.flash)),8+10*math.min(1,game.flash));
graphics.drawCircle(flashRing,game.mega.x,game.mega.y,72+(1-math.min(1,game.flash))*90);flashRing.delete();
}
}
var drawLeakTethers=function(graphics){
var leak;
for(i,e in game.entities) if(e.kind=="leak" && e.state=="orbit") leak=e;
if(!leak) return;
for(i,e in game.entities){
if(e.kind=="model" && e.state=="orbit" && e.boosted){
var pen=gdip.pen(alphaColor(0xFF54FFD3,80+45*math.sin(game.pulse/65+i)),1.5);
graphics.drawLine(pen,leak.x,leak.y,e.x,e.y);pen.delete();
}
}
}
var drawGag=function(graphics){
if(game.gagTime<=0) return;
var age=game.gagMax-game.gagTime;
var opacity=math.min(1,age/0.10,game.gagTime/0.16);
var lift=(1-opacity)*10;
var shadow=gdip.solidBrush(alphaColor(0xFF000000,135*opacity));
var box=gdip.solidBrush(alphaColor(0xFF10202D,245*opacity));
var edge=gdip.pen(alphaColor(game.gagColor,240*opacity),2.4);
graphics.fillRoundRect(shadow,30,334-lift,270,60,20);
graphics.fillRoundRect(box,24,328-lift,270,60,20);
graphics.drawRoundRect(edge,24,328-lift,270,60,20);
graphics.fillPolygon(box,[[176,388-lift],[208,388-lift],[192,505-lift]]);
drawText(graphics,game.gagText,FONT_18B,36,334-lift,246,46,alphaColor(game.gagColor,255*opacity),1);
edge.delete();box.delete();shadow.delete();
}
var drawHud=function(graphics){
var data=levelData();
var remaining=activeModelCount();
var pill=gdip.solidBrush(0xA5091724);var border=gdip.pen(0x4268C7DA,1);
graphics.fillRoundRect(pill,24,104,214,70,18);graphics.drawRoundRect(border,24,104,214,70,18);
drawText(graphics,"待返回模型",FONT_11,42,114,92,18,0xAFC6DDE7,0);
drawText(graphics,tostring(remaining),FONT_32B,38,130,56,38,data.accent,0);
drawText(graphics,"得分 "++game.score,FONT_12,101,135,120,23,0xFFE4F8FF,0);
border.delete();pill.delete();
var modeText=RELAXED_AGI_MODE ? "A · G · I 缓冲" : "一条即失败";
drawText(graphics,modeText,FONT_11,875,103,155,20,0xAFC8DFE8,1);
var letters=['A','G','I'];
for(i,ch in letters){
var x=901+(i-1)*46;var lit=game.leaks>=i;
var fill=gdip.solidBrush(lit ? 0xE9FF4D8B : 0x55132735);
var edge=gdip.pen(lit ? 0xFFFFB7CF : 0x57608390,1.5);
graphics.fillCircle(fill,x,145,17);graphics.drawCircle(edge,x,145,17);
drawText(graphics,ch,FONT_14B,x-14,132,28,27,lit ? 0xFFFFFFFF : 0x7AC2D3DB,1);
edge.delete();fill.delete();
}
if(game.chainCount>1 && game.chainTime>0){
var scale=1+0.08*math.sin(game.pulse/45);
var megaText=game.mega || game.chainCount>=4;
var w=(megaText ? 224 : 150)*scale;var h=(megaText ? 48 : 42)*scale;
var box=gdip.solidBrush(megaText ? 0xEFFFF0A2 : 0xB7FFB92F);graphics.fillRoundRect(box,CX-w/2,528-h/2,w,h,20);box.delete();
drawText(graphics,(megaText ? "一嘴大爆破 ×" : "连锁爆破 ×")++game.chainCount,megaText ? FONT_24B : FONT_18B,CX-w/2,528-h/2,w,h,0xFF3A210B,1);
}
var status=game.statusTime>0 ? game.status : "等目标穿过 TEST LINE → 点击任意位置";
var statusBox=gdip.solidBrush(0xF507131F);graphics.fillRoundRect(statusBox,300,568,728,28,14);statusBox.delete();
drawText(graphics,status,FONT_13,316,569,696,26,game.statusTime>0 ? 0xFFF4E8C5 : 0xCFE1F5F8,1);
if(game.intro>0 && game.state==STATE_PLAY){
//保持清晰,最后 0.45 秒快速淡出,避免长期残留成“幽灵 UI”。
var alpha=math.min(225,game.intro/0.45*225);
//首局提示收在鹈鹕旁边,不覆盖漩涡、轨道与版本泡泡。
var box=gdip.solidBrush(alphaColor(0xFF071521,alpha));var edge=gdip.pen(alphaColor(data.accent,alpha),1.5);
graphics.fillRoundRect(box,24,452,242,60,18);graphics.drawRoundRect(edge,24,452,242,60,18);
drawText(graphics,"目标过线 · 点任意处",FONT_14B,34,458,222,25,alphaColor(0xFFFFFFFF,alpha),1);
drawText(graphics,"长嘴会命中线路上的第一个物体",FONT_10,34,483,222,18,alphaColor(data.accent,alpha),1);
edge.delete();box.delete();
}
drawGag(graphics);
}
var drawResult=function(graphics){
if(game.state==STATE_PLAY) return;
var failed=game.state==STATE_FAILED;
var mask=gdip.solidBrush(failed ? 0x741C0615 : 0x68102027);
graphics.fillRoundRect(mask,274,177,692,306,30);mask.delete();
var glow=gdip.pen(failed ? 0xB7FF5B92 : 0xB45EFFE0,8);
var edge=gdip.pen(failed ? 0xFFFF9DBC : 0xFFB8FFF0,2);
graphics.drawRoundRect(glow,280,183,680,294,28);graphics.drawRoundRect(edge,280,183,680,294,28);
edge.delete();glow.delete();
if(failed){
drawText(graphics,"已实现 AGI!",FONT_44B,310,220,620,74,0xFFFFD6E4,1);
drawText(graphics,"发布搞错了 · 上传错了",FONT_18B,310,295,620,34,0xFFFF7FA8,1);
drawText(graphics,"上传的是炼废版,但会场已经开始鼓掌。",FONT_13,310,346,620,28,0xFFEED9E0,1);
drawText(graphics,"点击任意位置 · 立即重开本关",FONT_14B,310,410,620,34,0xFFFFFFFF,1);
}
else{
drawText(graphics,"全部返回训练池",FONT_32B,310,220,620,58,0xFFCBFFF2,1);
drawText(graphics,"今天仍未 AGI。",FONT_24B,310,282,620,42,0xFF65F0D0,1);
var detail=game.level==#levels ? "大的炸完了,小的回池了;上传前却发现选错了 checkpoint。" : "漂亮的时机判断:模型继续训练,版本数字只是数字。";
drawText(graphics,detail,FONT_13,310,346,620,28,0xFFE1F5F2,1);
var nextText=game.level==#levels ? "点击任意位置 · 再守一轮" : "点击任意位置 · 下一关";
drawText(graphics,nextText,FONT_14B,310,410,620,34,0xFFFFFFFF,1);
}
}
// -------------------- 输入与绘图事件 --------------------
winform.pelicanCanvas.onMouseDown=function(wParam,lParam){
if((wParam&1)==0) return;
beginStrike();
}
winform.pelicanCanvas.dlgCode=4/*_DLGC_WANTALLKEYS*/;
winform.pelicanCanvas.onKeyDown=function(vk){
if(vk==0x20/*_VK_SPACE*/) beginStrike();
elseif(vk==0x52/*R*/) resetLevel(game.level);
elseif(vk==0x4D/*M*/){
game.muted=!game.muted;
if(game.muted && midiOut) midiOut.reset();
setStatus(game.muted ? "事件音效已关闭" : "事件音效已开启",0.8);
}
}
winform.pelicanCanvas.onDrawBackground=function(graphics,rc,backgroundColor,color){return true;}
winform.pelicanCanvas.onDrawForeground=function(graphics,rc,foregroundRect,foregroundColor,color,font){
var dpiX,dpiY=winform.dpiScale(1,1);
if(math.abs(CACHE_SCALE-dpiX)>0.001){CACHE_SCALE=dpiX;sceneDirty=true;}
if(sceneDirty || !sceneCache) buildSceneCache();
graphics.interpolationMode=3/*_InterpolationModeBilinear*/;
graphics.drawImageRect(sceneCache,0,0,rc.width,rc.height);
var saved=graphics.save();
graphics.scale(dpiX,dpiY);
graphics.smoothingMode=4/*_SmoothingModeAntiAlias*/;
graphics.textRenderingHint=4/*_TextRenderingHintAntiAlias*/;
if(game.screenShake>0){
graphics.translate(math.sin(game.pulse/15)*game.screenShake*3,math.cos(game.pulse/19)*game.screenShake*2);
}
drawVortex(graphics);
drawLeakTethers(graphics);
drawCinemaEffects(graphics);
drawActiveLine(graphics);
drawPoolWater(graphics);
drawEntities(graphics);
drawEffects(graphics);
drawPelican(graphics);
drawHud(graphics);
drawResult(graphics);
graphics.restore(saved);
}
winform.pelicanCanvas.onAnimation=function(prevState,beginning,change,timestamp,duration,deltaMs){
deltaMs=math.min(deltaMs,55);
var dt=deltaMs/1000;
game.pulse+=deltaMs;
game.cooldown=math.max(0,game.cooldown-dt);
game.stun=math.max(0,game.stun-dt);
game.statusTime=math.max(0,game.statusTime-dt);
game.chainTime=math.max(0,game.chainTime-dt);
game.gagTime=math.max(0,game.gagTime-dt);
game.intro=math.max(0,game.intro-dt);
game.neckWobble=math.max(0,game.neckWobble-dt*2.6);
game.screenShake=math.max(0,game.screenShake-dt*4.5);
game.pelicanBlast=math.max(0,game.pelicanBlast-dt);
game.flash=math.max(0,game.flash-dt*3.0);
if(game.mega){game.mega.life-=dt;if(game.mega.life<=0) game.mega=null;}
if(game.state!=STATE_PLAY) game.resultTime+=dt;
updateStrike(dt);
if(game.state==STATE_PLAY) updateGame(dt);
else updateShocks(dt);
updateFalling(dt);
updateParticles(dt);
game.lineReady=findFirstLineHit()!=null;
return true;
}
winform.onClose=function(){
if(midiOut){midiOut.reset();midiOut.close();midiOut=null;}
if(megaImageAttributes){megaImageAttributes.delete();megaImageAttributes=null;}
if(megaSprite){megaSprite.delete();megaSprite=null;}
}
resetLevel(1);
winform.show();
winform.pelicanCanvas.setFocus();
winform.pelicanCanvas.startAnimation(16);
win.loopMessage();
Markdown 格式