Newer
Older
rpg / packages / engine / src / anim / flash.ts
/**
 * Хит-флэш: лерп цвета tint от исходного к «вспышке» и обратно.
 * Чистая логика (без Pixi) — результат применимо к любому числовому свойству.
 */

export class TintFlash {
    private elapsed: number | null = null;
    /** tint на момент запуска (возвращается к нему по окончании). */
    private base: number;

    /**
     * @param from исходный tint (например 0xffffff)
     * @param to цвет вспышки
     * @param seconds полная длительность (туда-обратно)
     */
    constructor(
        from: number,
        private readonly to: number,
        private readonly seconds: number
    ) {
        this.base = from;
    }

    /** Запустить (перезапускается с нуля). */
    start(): void {
        this.elapsed = 0;
    }

    /**
     * Обновить; возвращает текущий tint или null, если флэш не активен.
     * При окончании возвращает исходный цвет.
     */
    update(dt: number): number | null {
        if (this.elapsed === null) return null;
        this.elapsed += dt;
        if (this.elapsed >= this.seconds) {
            this.elapsed = null;
            return this.base;
        }
        // треугольная волна: 0..1..0
        const t = 1 - Math.abs(this.elapsed / this.seconds - 0.5) * 2;
        return lerpColor(this.base, this.to, t);
    }

    get active(): boolean {
        return this.elapsed !== null;
    }
}

/** Лерп двух цветов 0xRRGGBB по каналам. */
export function lerpColor(a: number, b: number, t: number): number {
    const ar = (a >> 16) & 0xff;
    const ag = (a >> 8) & 0xff;
    const ab = a & 0xff;
    const br = (b >> 16) & 0xff;
    const bg = (b >> 8) & 0xff;
    const bb = b & 0xff;
    const r = Math.round(ar + (br - ar) * t);
    const g = Math.round(ag + (bg - ag) * t);
    const bl = Math.round(ab + (bb - ab) * t);
    return (r << 16) | (g << 8) | bl;
}