Конечные автоматы в менюшном движке. Реализуем доисторическое приключение на ink. Часть 2
Продолжаем первую часть. Пишем вступление к игре и вход в основной параграф:
Для удобства сначала пройдём через узел инициализации, а затем уже войдём в главный узел игры, в котором будем крутиться до самого конца. В него добавим реакции на основные глаголы игры.
Ну вот, некий каркас из узлов есть, теперь добавим функции, которые будут отражать различные состояния объектов игры. И добавим их на печать в главный узел.
Теперь осталось только добавить «мозг» всей игры — функцию обработки конечного автомата. На вход её будет поступать тип команды игрока, в качестве результата она будет менять состояния героя, динозавра и копья, а также соответствующую реакцию на событие. Приведу пример пока только для изменения состояния динозавра.
В этой части рассмотрен простой способ реализации автомата на ink. Полный исходный код и особенности оформления будут в следующей части.
Доисторическая схватка
Если вы готовы, то выберите
* [Начать]
Лёгкий ветерок над пустынной равниной дарит небольшую прохладу после знойного дня. Охотник прислонился к стволу дерева и спокойно наблюдает за магическим пламенем. В этот год ему удасться сохранить его, если неподалёку отыщется еще несколько деревьев. Верное копьё, с каменным наконечником лежит возле левой ноги. Небольшой шорох из ближайших кустов и уже его руки крепко сжимают древко. Только не это, кажется на этой небогатой земле появился еще один охотник - не знающий пощады. Зубастая морда высунулась из-за кустов и начался древнейший танец смерти.
-> init_and_start_knot
-> END
Для удобства сначала пройдём через узел инициализации, а затем уже войдём в главный узел игры, в котором будем крутиться до самого конца. В него добавим реакции на основные глаголы игры.
//Узел для инициализации значений переменных
=== init_and_start_knot ===
VAR is_end = false //признак окончания игры
...
->game_knot
//Узел игры
=== game_knot ===
{is_end == true: -> END}
+ [Ждать]
->game_knot
+ [Метнуть копьё]
->game_knot
+ [Лезть на дерево]
->game_knot
+ [Ударить ветку]
->game_knot
-> END
Ну вот, некий каркас из узлов есть, теперь добавим функции, которые будут отражать различные состояния объектов игры. И добавим их на печать в главный узел.
//Узел игры
=== game_knot ===
{is_end == true: -> END}
{print_hero_state(hero_state)} <>
{print_dino_state(dino_state)} <>
{print_pike_state(pike_state)}
+ [Ждать]
->game_knot
+ [Метнуть копьё]
->game_knot
+ [Лезть на дерево]
->game_knot
+ [Ударить ветку]
->game_knot
-> END
//Состояния героя
=== function print_hero_state(state) ===
{
- state == far_tree:
~ return "Охотник сквозь пламя костра видит раскидистое дерево."
- state == near_tree:
~ return "Охотник стоит под деревом."
- state == up_tree:
~ return "Охотник на дереве, крепко держится за ствол."
}
//Состояния динозавра
=== function print_dino_state(state) ===
{
...
}
//Состояния копья
=== function print_pike_state(state) ===
{
...
}
Теперь осталось только добавить «мозг» всей игры — функцию обработки конечного автомата. На вход её будет поступать тип команды игрока, в качестве результата она будет менять состояния героя, динозавра и копья, а также соответствующую реакцию на событие. Приведу пример пока только для изменения состояния динозавра.
//Узел игры
=== game_knot ===
{is_end == true: -> END}
{print_hero_state(hero_state)} <>
{print_dino_state(dino_state)} <>
{print_pike_state(pike_state)}
+ [Ждать]
{update_states(cmd_wait)}
->game_knot
+ [Метнуть копьё]
{update_states(cmd_throw)}
->game_knot
+ [Лезть на дерево]
{update_states(cmd_up)}
->game_knot
+ [Ударить ветку]
{update_states(cmd_hit)}
->game_knot
-> END
//Функция обработчик состояний
=== function update_states(cmd_type)
//По умолчанию выдаём отклик, похожий на инстед-реализацию
~ temp action_result = "Не сработало. "
//Запоминаем текущие состояния, чтобы автоматы работали параллельно, при изменении в ходе обработки
~ temp curr_dino_state = dino_state
~ temp curr_pike_state = pike_state
~ temp curr_hero_state = hero_state
//Обновляем динозавра
{
-dino_state == dino_visible:
//Если бросаем копье, когда динозавр видим, то он убегает, иначе он просто скрывается
{curr_hero_state == near_tree && cmd_type == cmd_throw:
~dino_state = dino_run
-else:
~dino_state = dino_hidden
}
{curr_hero_state != near_tree && cmd_type == cmd_throw:
~action_result = "Охотник не может подобрать удобную позицию чтобы метнуть копьё, зверюга очень изворотливая."
}
-else:
{cmd_type == cmd_throw:
~action_result = "Присмотревшись к кустам, охотник понимает, что вслепую атаковать бессмысленно."
}
//динозавр снова на виду
~dino_state = dino_visible
}
...
~return action_result
В этой части рассмотрен простой способ реализации автомата на ink. Полный исходный код и особенности оформления будут в следующей части.
1. По умолчанию переменные используются в булевом контексте, поэтому сравнение с is_end можно записать вот так:
2. Если единственная задача функции — просто выводить игровой текст, то это можно сделать чуть проще: