/**
 * Реестр объектов, тикаемых движком от фиксированного шага: эффекты,
 * аниматоры, вспышки. Инстанс живёт в Engine (`engine.fx`) и тикается
 * между tween-ами и сценами; допускается и локальный инстанс в сцене.
 *
 * Владение отсутствует: запись с `destroyed === true` (Pixi-объекты
 * выставляют его при destroy) вычищается сама при очередном update.
 */

/** Всё, что движок может тикать; destroyed — признак самозачистки. */
export interface Updatable {
    update(dt: number): void;
    destroyed?: boolean;
}

export class Updatables {
    private list: Updatable[] = [];

    /** Добавить и вернуть тот же объект — удобно: `engine.fx.add(emitter)`. */
    add(u: Updatable): Updatable {
        if (!this.list.includes(u)) this.list.push(u);
        return u;
    }

    remove(u: Updatable): void {
        const i = this.list.indexOf(u);
        if (i !== -1) this.list.splice(i, 1);
    }

    clear(): void {
        this.list.length = 0;
    }

    /** Обойти живые записи (например, чтобы погасить все эффекты слоя). */
    forEach(fn: (u: Updatable) => void): void {
        for (const u of this.list) fn(u);
    }

    /**
     * Тик в порядке добавления; разрушенные записи не тикаются (Pixi после
     * destroy обнуляет transform — касаться их нельзя) и вычищаются
     * компактом на месте (без filter — тик не должен аллоцировать).
     */
    update(dt: number): void {
        let w = 0;
        for (const u of this.list) {
            if (u.destroyed) continue;
            u.update(dt);
            if (!u.destroyed) this.list[w++] = u; // update мог разрушить сам объект
        }
        this.list.length = w;
    }

    get count(): number {
        return this.list.length;
    }
}