import { Container } from 'pixi.js';
import type { Updatable } from '../../core/Updatables';
import { sampleFade, type FxFadeSpec } from './fxSim';
/** Опции растворения: математика (FxFadeSpec) + жизненный цикл вьюхи. */
export interface FxFadeOptions extends FxFadeSpec {
/** true — не уничтожать вьюху в конце (только альфа). */
keep?: boolean;
/** Колбэк завершения (в т.ч. после destroy вьюхи). */
onDone?: () => void;
}
/**
* Растворение/проявление произвольной вьюхи + авто-удаление. Не display-объект:
* тикается в реестре, применяет альфу к чужой вьюхе. В конце removeChild +
* destroy({children: true}) — с защитой от двойного destroy (вьюху могли
* уничтожить извне, пока эффект играл).
*/
export class FxFade implements Updatable {
private t = 0;
private finished = false;
private readonly from: number;
constructor(
private readonly view: Container,
private readonly opts: FxFadeOptions
) {
this.from = view.alpha;
}
/**
* Прекратить эффект: вернуть базовую альфу; вьюху, которую эффект уничтожил
* бы в конце (!keep), гасим сразу — контракт fx: cancel = конец эффекта.
*/
cancel(): void {
if (this.finished) return;
this.finished = true;
if (this.view.destroyed) return;
this.view.alpha = this.from;
if (!this.opts.keep) {
this.view.parent?.removeChild(this.view);
this.view.destroy({ children: true });
}
}
/** Вьюха разрушена извне или эффект закончился — запись вычистится сама. */
get destroyed(): boolean {
return this.finished || this.view.destroyed;
}
update(dt: number): void {
if (this.finished) return;
if (this.view.destroyed) return; // реестр вычистит по destroyed
this.t += dt;
this.view.alpha = sampleFade(this.t, this.from, this.opts);
const total = (this.opts.delay ?? 0) + this.opts.duration;
if (this.t >= total - 1e-6) { // эпсилон: накопление 1/60 не дотягивает до границы
this.finished = true;
if (!this.opts.keep) {
this.view.parent?.removeChild(this.view);
this.view.destroy({ children: true });
}
this.opts.onDone?.();
}
}
}