Машина состояний

Части и запчасти к проектам, дополнительное программное обеспечение.

Машина состояний

Сообщение SunLiiL 20 сен 2015, 20:54

Решил прикрутить к своему проектику стейт машину. Погуглил, почитал статеек, в итоге очень понравилась реализация Appccelerate State Machine. Вот только идет она чисто под .net framework 4.x и с юнити просто так не дружит. Благо сорцы открыты - портировал либу под юнити :ymparty: . Выпилил Active State Machine, и оставил только Passive State Machine. Отличия между ними только в том, что первая может работать в разных потоках, кто пожелает может и эту часть портировать :ymsmug: Документация вся работает так же, как и для источника(ну еще логгеры убрал, которые есть у источника).

Из плюсов:
- возможность создавать иерархические машины состояний
- fluent стиль использования
- можно задавать свои функции, которые будут отрабатывать при входе/выходе из состояния и во время его работы
- можно задавать условные развлетвления (пойти к состоянию А, если ... иначе к Б)
... и тд

Все лежит тут (собранная dll - нужно положить в Assets->Plugins и исходники в архиве)

Пример с лифтом, взятый из документации и обкатанный в юнити:

Синтаксис:
Используется csharp
using StateMachine;
using UnityEngine;

namespace Game.Assets.Game.Scripts.Hunter
{
    public enum States
    {
        Healthy,
        OnFloor,
        Moving,
        MovingUp,
        MovingDown,
        DoorClosed,
        DoorOpen,
        Error
    }

    public enum Events
    {
        ErrorOccured,
        Reset,
        CloseDoor,
        OpenDoor,
        GoUp,
        GoDown,
        Stop
    }

    public class FSMTest : MonoBehaviour
    {
        private PassiveStateMachine<States, Events> _elevatorFsm;

        private void Start()
        {
            // ставим в очередь несколько событий
            _elevatorFsm.Fire(Events.ErrorOccured);
            _elevatorFsm.Fire(Events.Reset);

            _elevatorFsm.Start();

            // исполнение событий
            _elevatorFsm.Fire(Events.OpenDoor);
            _elevatorFsm.Fire(Events.CloseDoor);
            _elevatorFsm.Fire(Events.GoUp);
            _elevatorFsm.Fire(Events.Stop);
            _elevatorFsm.Fire(Events.OpenDoor);

            _elevatorFsm.Stop();
        }

        private void Awake()
        {
            _elevatorFsm = new PassiveStateMachine<States, Events>("Лифт");

            _elevatorFsm.DefineHierarchyOn(States.Healthy)
                .WithHistoryType(HistoryType.Deep)
                .WithInitialSubState(States.OnFloor)
                .WithSubState(States.Moving);

            _elevatorFsm.DefineHierarchyOn(States.Moving)
                .WithHistoryType(HistoryType.Shallow)
                .WithInitialSubState(States.MovingUp)
                .WithSubState(States.MovingDown);

            _elevatorFsm.DefineHierarchyOn(States.OnFloor)
                .WithHistoryType(HistoryType.None)
                .WithInitialSubState(States.DoorClosed)
                .WithSubState(States.DoorOpen);

            _elevatorFsm.In(States.Healthy)
                .On(Events.ErrorOccured).Goto(States.Error);

            _elevatorFsm.In(States.Error)
                .On(Events.Reset).Goto(States.Healthy)
                .On(Events.ErrorOccured);

            _elevatorFsm.In(States.OnFloor)
                .ExecuteOnEntry(this.AnnounceFloor)
                .ExecuteOnExit(Beep)
                .ExecuteOnExit(Beep) // бип бип еще раз
                .On(Events.CloseDoor).Goto(States.DoorClosed)
                .On(Events.OpenDoor).Goto(States.DoorOpen)
                .On(Events.GoUp)
                    .If(CheckOverload).Goto(States.MovingUp)
                    .Otherwise().Execute(this.AnnounceOverload)
                .On(Events.GoDown)
                    .If(CheckOverload).Goto(States.MovingDown)
                    .Otherwise().Execute(this.AnnounceOverload);

            _elevatorFsm.In(States.Moving)
                .On(Events.Stop).Goto(States.OnFloor);

            _elevatorFsm.Initialize(States.OnFloor);
        }

        private void AnnounceOverload()
        {
            Debug.Log("Перевес!");
        }

        private bool CheckOverload()
        {
            return false;
        }

        private void Beep()
        {
            Debug.Log("БИП БИП!");
        }

        private void AnnounceFloor()
        {
            Debug.Log("Приехали на этаж!");
        }
    }
}
 


Скорее всего должно спокойно все работать на разных платформах, но гарантии нет.

P.S. Надеюсь в правильном месте создал тему :-?
Аватара пользователя
SunLiiL
UNIт
 
Сообщения: 73
Зарегистрирован: 27 июл 2013, 10:45
Откуда: Набережные Челны, р. Татарстан
Skype: sunliil

Вернуться в Компоненты (Копилка)

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3