Конечный автомат вместо десяти флагов
Каждая моя игра на раннем этапе выглядела одинаково: горстка булевых флагов, которые где-то включаются, а где-то выключаются. isAnimating, waitingForInput, isPaused, levelEnding. Пока их три — терпимо. Когда стало восемь, я поймал баг, из-за которого игрок мог сделать ход прямо во время анимации проигрыша, и понял, что дальше так нельзя.
Проблема флагов в том, что они допускают невозможные сочетания. Восемь булевых значений — это 256 комбинаций, а осмысленных из них штук шесть. Остальные 250 — это те самые «а как ты вообще сюда попал» баги.
Одна переменная состояния
Конечный автомат (state machine) переворачивает подход: вместо десяти «да/нет» одна переменная, у которой всего несколько разрешённых значений. В любой момент игра ровно в одном состоянии.
const State = {
IDLE: "idle", // ждём ввода игрока
ANIMATING: "animating", // проигрываем анимацию хода
RESOLVING: "resolving", // считаем последствия
LEVEL_END: "level_end", // экран победы/поражения
};
let state = State.IDLE;
Ввод игрока принимается ровно в одном состоянии:
function onTap(x, y) {
if (state !== State.IDLE) return; // всё, одна строка
state = State.ANIMATING;
playMove(x, y, () => { state = State.RESOLVING; });
}
Та самая проверка if (state !== State.IDLE) return закрывает целый класс багов, на которые раньше уходили вечера. Нельзя нажать во время анимации — потому что состояние уже не IDLE.
Переходы в одном месте
Второе, что даёт автомат, — все правила переходов собраны в одной функции, а не размазаны по обработчикам. Я обычно завожу явную таблицу «из какого состояния в какое можно», и любой недопустимый переход — это громкая ошибка в логе, а не тихо испорченный кадр.
Если переход состояния произошёл не там, где положено, я хочу узнать об этом сразу и в консоли, а не через неделю от игрока.
Когда это перебор
Честно: для совсем простой аркады на одну кнопку автомат может быть избыточен — там и двух флагов хватит. Я достаю его, когда состояний становится больше четырёх или когда появляются анимации, во время которых ввод надо блокировать. Для пошаговых игр это происходит почти сразу.
С тех пор я начинаю новую игру не с графики, а с трёх строк: список состояний, стартовое состояние, функция перехода. Дальше всё нанизывается на этот скелет, и «невозможные» баги просто перестают возникать.