import { Container } from 'pixi.js';
import type { Scene } from '../scene/SceneManager';
import type { MenuList } from './MenuList';
import { readMenuInput, type MenuActionMap } from './menuInput';
/**
* Базовая сцена-меню: панель поверх вызывающей сцены (push/pop) с клавиатурной
* навигацией. Устраняет дублирование «up/down/confirm/cancel → moveCursor/
* activate + гард перехода» из четырёх сцен игры. Игра строит панель и меню
* своим стилем в build(); ввод читается по карте действий сцены.
*/
export interface MenuSceneContext {
/** Ввод (InputManager или заглушка). */
input: { isActionJustPressed(action: string): boolean };
/** true, пока стек сцен в переходе — ввод блокируется. */
inputBlocked(): boolean;
}
export abstract class MenuSceneBase implements Scene {
/** Корень вью сцены; build() добавляет его в uiRoot. */
protected readonly view = new Container();
/** Список меню (null — сцена без списка, например просмотр сумки). */
protected menu: MenuList | null = null;
protected constructor(
private readonly ctx: MenuSceneContext,
private readonly actions: MenuActionMap
) {}
/** Построить панель/заголовок/меню и добавить this.view в uiRoot. */
protected abstract build(): void;
enter(): void {
this.build();
}
exit(): void {
this.view.destroy({ children: true });
this.menu = null;
}
render(): void {}
update(_dt: number): void {
if (this.ctx.inputBlocked()) return;
const index = this.menu?.index ?? 0;
for (const ev of readMenuInput(this.ctx.input, index, this.actions)) {
switch (ev.kind) {
case 'move':
this.onMove(ev.delta, ev.index);
break;
case 'adjust':
this.onAdjust(ev.delta, ev.index);
break;
case 'confirm':
this.onConfirm(ev.index);
break;
case 'cancel':
this.onCancel();
break;
case 'action':
this.onAction(ev.action, ev.index);
break;
}
}
}
/** Дефолт: двигать курсор списка. */
protected onMove(delta: number, _index: number): void {
this.menu?.moveCursor(delta);
}
/** Подстройка значения выбранной строки (настройки); по умолчанию — ничего. */
protected onAdjust(_delta: number, _index: number): void {}
/** Дефолт: активировать кнопку под фокусом. */
protected onConfirm(_index: number): void {
this.menu?.activate();
}
/** Назад/закрыть; по умолчанию — ничего (главное меню не закрывается). */
protected onCancel(): void {}
/** Прочее действие сцены (extra из карты); по умолчанию — ничего. */
protected onAction(_action: string, _index: number): void {}
}