import { Graphics } from 'pixi.js';
import type { Updatable } from '../../core/Updatables';
import { sampleRing, ringDuration, type FxRingSpec, type FxRingSample } from './fxSim';
/**
* Кольцо/волна: расходящаяся или сходящаяся окружность (или ромб — «footprint»
* зоны). repeat > 1 — телеграф зоны (проходы с паузами); repeat: Infinity —
* зацикленный индикатор, гасится только cancel(). Перерисовка каждый тик
* (clear + один stroke) — тот же приём, что у рукописных колец боевых вьюх.
*/
export class FxRing extends Graphics implements Updatable {
private t = 0;
private cancelled = false;
constructor(private readonly spec: FxRingSpec) {
super();
this.draw(sampleRing(0, spec));
}
/** Досрочно погасить (смена телеграфа, exit сцены). */
cancel(): void {
if (this.cancelled) return;
this.cancelled = true;
this.destroy();
}
/** true, когда все проходы сыграны (или кольцо погашено). */
get done(): boolean {
return this.cancelled || this.t >= ringDuration(this.spec) - 1e-6;
}
update(dt: number): void {
if (this.destroyed) return;
this.t += dt;
this.draw(sampleRing(this.t, this.spec));
if (this.done) this.destroy();
}
private draw(s: FxRingSample): void {
this.clear();
if (this.spec.fill) {
this.shapePath(s.radius).fill({
color: this.spec.fill,
alpha: (this.spec.fillAlpha ?? 0.25) * s.alpha
});
}
this.shapePath(s.radius).stroke({
color: this.spec.color,
width: this.spec.width ?? 1,
alpha: s.alpha
});
}
/** Контур зоны текущего радиуса: круг или ромб (квадрат, повёрнутый на 45°). */
private shapePath(r: number): this {
if (this.spec.shape === 'diamond') {
return this.poly([0, -r, r, 0, 0, r, -r, 0]);
}
return this.circle(0, 0, r);
}
}