Конечный автомат (Finite State Machine, FSM) представляет собой математическую модель, описывающую поведение объекта через ограниченное множество состояний и переходы между ними. В игровой логике FSM используется для управления персонажами, объектами окружения, ИИ противников и взаимодействием игровых систем.
Ключевыми компонентами FSM являются:
FSM обеспечивает структурированность кода, упрощает сопровождение и позволяет отделить логику поведения от остальных частей игры.
Babylon.js не имеет встроенного класса конечного автомата, поэтому чаще всего FSM реализуется вручную через классы JavaScript или через сторонние библиотеки. Основная структура FSM выглядит следующим образом:
class State {
constructor(name, onEn ter = null, onUpd ate = null, onE xit = null) {
this.name = name;
this.onEn ter = onEnter;
this.onUpd ate = onUpdate;
this.onE xit = onExit;
}
}
class StateMachine {
constructor(initialState) {
this.currentState = initialState;
if (this.currentState.onEnter) {
this.currentState.onEnter();
}
}
changeState(newState) {
if (this.currentState.onExit) {
this.currentState.onExit();
}
this.currentState = newState;
if (this.currentState.onEnter) {
this.currentState.onEnter();
}
}
update() {
if (this.currentState.onUpdate) {
this.currentState.onUpdate();
}
}
}
Ключевые моменты реализации:
onEnter вызывается один раз при входе в состояние.onUpdate выполняется каждый кадр, пока объект находится
в состоянии.onExit выполняется при выходе из состояния.update обычно вызывается внутри основного
игрового цикла Babylon.js
(scene.onBeforeRenderObservable.add).Пример реализации FSM для персонажа с состояниями «стояние», «ходьба» и «атака»:
const idleState = new State(
"idle",
() => console.log("Персонаж стоит"),
() => {
if (input.isKeyPressed("ArrowUp")) {
fsm.changeState(walkState);
}
}
);
const walkState = new State(
"walk",
() => console.log("Персонаж идет"),
() => {
if (!input.isKeyPressed("ArrowUp")) {
fsm.changeState(idleState);
}
if (input.isKeyPressed("Space")) {
fsm.changeState(attackState);
}
}
);
const attackState = new State(
"attack",
() => console.log("Персонаж атакует"),
() => {},
() => console.log("Персонаж завершил атаку")
);
const fsm = new StateMachine(idleState);
scene.onBeforeRenderObservable.add(() => {
fsm.update();
});
Особенности такого подхода:
Для NPC и врагов FSM позволяет реализовать сложное поведение, включая патрулирование, преследование игрока и реагирование на события:
const patrolState = new State(
"patrol",
() => startPatrol(),
() => {
if (playerInSight()) {
fsm.changeState(chaseState);
}
}
);
const chaseState = new State(
"chase",
() => startChase(),
() => {
if (!playerInSight()) {
fsm.changeState(patrolState);
}
if (playerClose()) {
fsm.changeState(attackState);
}
}
);
const attackState = new State(
"attack",
() => performAttack(),
() => {
if (!playerClose()) {
fsm.changeState(chaseState);
}
}
);
const fsm = new StateMachine(patrolState);
scene.onBeforeRenderObservable.add(() => fsm.update());
Преимущества FSM для ИИ:
Состояния с таймерами: можно добавлять автоматический переход через заданное время:
const stunnedState = new State(
"stunned",
() => { this.timer = 3; },
() => {
this.timer -= scene.getEngine().getDeltaTime() / 1000;
if (this.timer <= 0) fsm.changeState(idleState);
}
);
Иерархические FSM (HFSM): состояния могут содержать вложенные FSM для более сложного поведения (например, «атака» → «подготовка», «удар», «откат»).
Комбинирование с анимациями Babylon.js: FSM идеально
подходит для переключения между анимациями через
scene.beginAnimation(mesh, from, to, loop) при входе в
состояние.
Конечные автоматы обеспечивают организованную и предсказуемую игровую логику, упрощают управление сложным поведением объектов и позволяют плавно интегрировать анимации, управление и ИИ в Babylon.js.