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; } }