# AI

Система ИИ строится на концепции “[finite state machine](https://tproger.ru/translations/finite-state-machines-theory-and-implementation/)” (версия не на стеке). Есть состояния и переходы между ними (как в аниматоре). Для того, чтобы создать компонент ИИ для сущности, надо создать объект в боте, в этот объект поместить компоненты “StateMachine”, “StateData” (лучше создать свой тип даты для разных ботов, унаследовав класс) и все типы состояний “State”, используемые в ИИ. Состояния создаются наследованием от класса “State\<T>”. В качестве “T” надо указать свой “StateDate” тип. В компоненте “StateMachine” надо построить граф со стейтами и переходами между ними. Стейты следует называть так же как и их классы (они привязываются по имени). “StateData” используется для хранения внешних ссылок и как интерфейс взаимодействия с внешними объектами.\


![](https://lh3.googleusercontent.com/rckXVOprjFtApf7IjWGgM1VH1BbXLr7lL2-RCLmMDj-7PM-kef09F9kb0NhP4K2IkUpmfVVvCgVqjI4bdh6IPpdAoCocZzBpN7nmsJdHbMbh0TsM_BGGOM0n7l-82wimvwBj4ngAQ7LjGn6xOQ)

![](https://lh6.googleusercontent.com/zqd70pnTMCQRTkn-gm-lIWgEOGCzXMduNOblcEXWQ7DeMI3Yh2rj7aNp3iw6IdekOqQoHjL3QmnbgNtCMYp8g59OtfSfFS6crNqpslAuIQyZCFikZXhsNf37liCGDjPuVM3LfAgwztj-fSrW1A)

В состоянии реализуется логика поведения и переходов. Для этого есть виртуальные методы “OnEnter”, “OnUpdate”, “OnExit”, которые вызываются при активации состояния, в апдейте если активно, и при выходе из него соответственно.

Чтобы перейти в другое состояние, надо вызвать метод “ChangeState” и в дженерике указать тип нового состояния. Хотя переходы между состояниями можно делать и в “OnUpdate” (или в “OnEnter”) при каком-либо условии, всё же рекомендуется это делать с помощью подписания на эвенты в “Start” методе.

Также в обновлении был добавлен виртуальный метод “RareUpdate”, который вызывается каждый 10 вызов апдейта. Свою задержку вызова можно установить в Awake через вызов метода “SetRareUpdateSkipFrames”

Чтобы избежать срабатывание кода в эвенте когда текущее состояние другое (если подписался в “Start”), надо в методе поставить в начале условие: “if (!IsCurrent()) reutrn;” “IsCurrent” возвращает является ли это состояние активным в данный момент

Данные об сущности рекомендуется хранить в вашей реализации “StateData”, а получить их можно через поле родителя всех стейтов “data” (например “data.Agent” получает NavMeshAgent, указанный в сцене в компоненте “StateData”). В качестве “Main” в “StateData” надо указывать ссылку на родительский (самый-самый) объект бота. Также НЕ рекомендуется менять состояния напрямую извне, иначе потом будет непонятно почему данное состояние поменялось в данный момент. Поэтому если хотите поменять состояние под влиянием чего-либо, эти данные надо передать сначала в реализацию “StateData”, а потом уже подписавшись (ValueObservable) из состояния на изменение этого значения думать делать переход или нет.
