Applying Unity DOTS for AI state machine

Hello everyone
I am trying to convert this code:

public class StateTransition
{
    public IState From;
    public IState To;
    public Func<bool> Condition;

    public StateTransition(IState from, IState to, Func<bool> condition)
    {
        From = from;
        To = to;
        Condition = condition;
    }
}
public class StateMachine
{
    private List<StateTransition> stateTransitions = new List<StateTransition>();
    private List<StateTransition> anyStateTransitions = new List<StateTransition>();
    private IState currentState;
    public IState CurrentState => currentState;
    public event Action<IState> OnStateChanged;

    public void AddAnyTransition(IState to, Func<bool> condition)
    {
        var stateTransition = new StateTransition(null, to, condition);
        anyStateTransitions.Add(stateTransition);
    }

    public void AddTransition(IState from, IState to, Func<bool> condition)
    {
        var stateTransition = new StateTransition(from, to, condition);
        stateTransitions.Add(stateTransition);
    }

    public void SetState(IState state)
    {
        if (currentState == state)
        {
            return;
        }
     
        currentState?.OnExit();

        currentState = state;
     
        //Debug.Log($"Changed to state {state}");
        currentState.OnEnter();
        OnStateChanged?.Invoke(currentState);
    }

    public void Tick()
    {
        if(MainManager.instance.isPlayerDead || MainManager.instance.didPlayerWin)
        {
            return;
        }
     
        var transition = CheckForTransition();
     
        if(transition!=null)
        {
            SetState(transition.To);
        }
     
        currentState.Tick();
    }

    private StateTransition CheckForTransition()
    {
        foreach (var transition in anyStateTransitions)
        {
            if (transition.Condition())
            {
                if(transition.To!= currentState)
                    return transition;
            }
        }
        foreach (var transition in  stateTransitions)
        {
            if (transition.From == currentState && transition.Condition())
            {
                return transition;
            }
        }

        return null;
    }
}

into Unity ECS to optimize the code and so far I have made the following changes:

public struct TickState : IComponentData {}
public struct OnEnterState : IComponentData {}
public struct OnExitState : IComponentData {}

public struct AIStateComponent : IComponentData {
    public IState state;
}
public struct CurrentStateComponent : IComponentData {
    public IState state;
}

public class StateTransitionSystem : SystemBase {
    protected override void OnUpdate() {
        Entities
            .WithAll<TickState>()
            .ForEach((Entity entity, ref CurrentStateComponent currentState, in AIStateComponent) => {
                stateComponent.state.Tick();
            }).ScheduleParallel();
     
        Entities
            .WithAll<OnEnterState>()
            .ForEach((Entity entity, ref CurrentStateComponent currentState, in AIStateComponent) => {
                stateComponent.state.OnEnter();
            }).ScheduleParallel();
     
        Entities
            .WithAll<OnExitState>()
            .ForEach((Entity entity, ref CurrentStateComponent currentState, in AIStateComponent) => {
                stateComponent.state.OnExit();
            }).ScheduleParallel();
    }
}

So I would like to ask for guidance and help to be sure if I am on the right track regarding the conversion and I still need to convert the following methods from the state machine class: AddAnyTransition, AddTransition, SetState, Tick and CheckForTransition

Please use code tags.

2 Likes

I have done so my mistake for not realizing it was an option

You can’t have interface fields in struct IComponentData. Polymorphism-style modularity isn’t really a first-class citizen in ECS. There are some third-party packages that have polymorphic structs with source generators. But otherwise, you will likely need to redesign how you think about state machines.

So what is your suggestion to implement Unity DOTS for this code if it’s possible

I personally wouldn’t try to convert generalized interface-based OOP code into ECS code. I’d instead analyze whatever problem this code was written to solve, and then find an ECS way to solve that problem instead. I can’t really answer more specifically than that, because I know nothing about what this state machine was used for.

The state machine was used for controlling the enemy behaviors, which currently are object instances, so it would mean either convert both to ECS and that would take a long time for implementation since it has a lot of dependencies

Well, if you want your state machine to be hybrid, then you need to use a class IComponentData or a GameObject component to store your state machine.

Could you show me an example of how you would convert it to IComponentData so I can better understand the conversion process

I don’t have one. I rarely use hybrid.