MatchMaster/assets/Script/RainbowOldOpening.ts
WIN-GKKD951VVMJ\Administrator 74cf4413b5 增加一版彩虹机制
2026-09-20 17:14:40 +08:00

78 lines
3.1 KiB
TypeScript

import RainbowTrail from "./RainbowTrail";
import RainbowBottleWater from "./RainbowBottleWater";
import { RAINBOW_CAST_SECONDS } from "./RainbowRules";
/** C 方案开局自动施放一次;地图在尾迹消散后才开放操作。 */
export default class RainbowOldOpening {
private flight: RainbowTrail;
private from: cc.Vec2;
private to: cc.Vec2;
private elapsed = 0;
private landed = false;
private disposed = false;
private hidden = false;
private hide = () => {
this.hidden = true;
if (this.flight) this.flight.update(true);
if (cc.isValid(this.bottle, true)) this.bottle.active = false;
};
private show = () => {
this.hidden = false;
if (!this.disposed && cc.isValid(this.bottle, true)) this.bottle.active = true;
};
constructor(parent: cc.Node, private bottle: cc.Node, to: cc.Vec2, private onLand: () => void) {
this.from = parent.convertToNodeSpaceAR(bottle.convertToWorldSpaceAR(cc.v2(0, 0)));
this.to = cc.v2(to.x, to.y);
bottle.active = true;
bottle.color = cc.Color.WHITE;
bottle.getComponent(cc.Sprite).fillRange = 1;
if (!bottle.getComponent(RainbowBottleWater)) bottle.addComponent(RainbowBottleWater);
this.flight = new RainbowTrail(parent, RAINBOW_CAST_SECONDS);
this.flight.node.setPosition(this.from);
// 转场结束前由地图保持暂停,不能让粒子在遮罩后先发射。
this.flight.update(true);
cc.game.on(cc.game.EVENT_HIDE, this.hide);
cc.game.on(cc.game.EVENT_SHOW, this.show);
}
/** 返回 true 表示飞行和尾迹均已结束;开局不依赖游戏倒计时。 */
update(dt: number, paused = false): boolean {
if (this.disposed) return true;
if (!this.flight.update(this.hidden || paused)) {
// RainbowTrail 已自行释放资源,不能在 dispose 中再销毁一次。
this.flight = null;
this.dispose();
return true;
}
if (this.hidden || paused || this.landed) return false;
this.elapsed += dt;
const t = Math.min(1, this.elapsed / RAINBOW_CAST_SECONDS);
// 与 B 同一条弧线:先抛到目标上方,再竖直落入目标。
const top = Math.max(this.from.y, this.to.y) + 180;
const controlY = top + Math.sqrt((top - this.from.y) * (top - this.to.y));
const u = 1 - t;
this.flight.node.setPosition(this.to.x + (this.from.x - this.to.x) * u * u,
u * u * this.from.y + 2 * u * t * controlY + t * t * this.to.y);
this.flight.setProgress(t);
if (t >= 1) {
this.landed = true;
this.flight.stop();
this.onLand();
}
return this.disposed;
}
dispose(): void {
if (this.disposed) return;
this.disposed = true;
if (this.flight) {
this.flight.destroy();
this.flight = null;
}
cc.game.off(cc.game.EVENT_HIDE, this.hide);
cc.game.off(cc.game.EVENT_SHOW, this.show);
if (cc.isValid(this.bottle, true)) this.bottle.active = false;
}
}