Рассмотрим код и структуру туториала на Godot — Hierarchical Finite State Machine.
Главный игрок представляет собой дочерний узел типа CharacterBody2D. Внутрь него вложен узел Node, который, в свою очередь, содержит ещё шесть узлов Node.
Внутри CharacterBody2D также находятся:
AnimationPlayer
Sprite2D
Marker2D — относительно него расположено тело игрока; отсюда с помощью таймера и Node2D могут создаваться пули.
Дополнительные узлы Marker2D — один для управления мечом, другой для подключения сцены меча.
Кроме того, у персонажа есть CollisionPolygon2D для обработки столкновений и специальная метка для отображения текущего состояния.
Главные классы сцены персонажа
Основные скрипты здесь — state.gd и state_machine.gd. В state.gd присутствует сигнал finished. Он испускается при наступлении какого-либо события, например:
Stagger вызывается после Idle,
Move — после Idle,
Jump — после Idle.
Изначально стек событий пуст, и в него добавляется первый элемент — узел Idle.
Далее рассмотрим функцию _enter_tree() в скрипте state_machine.gd.
func _enter_tree() -> void:
if start_state.is_empty():
start_state = get_child(0).get_path()
for child in get_children():
var err: bool = child.finished.connect(_change_state)
if err:
printerr(err)
initialize(start_state)
Если в узле start_state ничего нет, в него добавляется первый дочерний узел — Idle. После этого запускается цикл по всем дочерним узлам, а именно по узлам типа Node: Idle, Move, Jump, Stagger, Attack, Die, которые вложены в узел StateMachine. Все сигналы finished этих узлов соединяются с методом _change_state. Рассмотрим подробнее этот метод.
func _change_state(state_name: String) -> void:
if not _active:
return
current_state.exit()
if state_name == "previous":
states_stack.pop_front()
else:
states_stack[0] = states_map[state_name]
current_state = states_stack[0]
state_changed.emit(current_state)
if state_name != "previous":
current_state.enter()
В этом методе изменяется узел текущего состояния — current_state, после чего испускается сигнал state_changed. Этот сигнал может использоваться для отображения текущего узла или для вызова сцены атаки (например, с помощью меча). Затем вызывается метод enter() у сцены текущего состояния — этот метод определён в файле state.gd.
Как показано на рисунке, в коде State.gd имеется сигнал finished. Он вызывается в любом месте наследуемых классов: Idle.gd, Move.gd, Jump.gd, Stagger.gd или Attack.gd. Этот сигнал инициирует вызов метода _change_state в StateMachine.gd, который, в свою очередь, испускается и связывается в player_state_machine либо с объектами атаки мечом, либо с выводом на экран текущего состояния.
Дополнительные элементы:
Сцена пуль: пули вылетают из игрока и генерируются по таймеру при нажатии на кнопку R.
Сцена меча: мечом можно ударить два раза, если часто нажимать на кнопку F.
Код игрока (player_controller): содержит функцию take_damage (не работает, поскольку в сцене нет второго врага), а также функцию set_dead, которая отключает физику игрока.
Переменная look_direction: используется для правильного позиционирования меча и пуль.
Сигнал direction_changed: испускается при изменении позиции игрока. Для пуль look_direction непосредственно задаёт направление полёта (direction).
WeaponPivot: сигнал direction_changed связывается с методом, управляющим углом вращения меча.
Конец.
Мы грубо и схематично рассмотрели программу Godot Hierarchical Finite State Machine. В следующих частях мы будем восстанавливать эту программу. Спасибо за внимание.
