78 lines
3.1 KiB
TypeScript
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;
|
|
}
|
|
}
|