Hello everyone,
Rather new programmer here trying to get my (first) state machine to work the way I want to. I based my state machine from this thread: C# Proper State Machine , specifically the state machine from @KelsoMRK (thank you btw). Also, I apologize if I use the incorrect language for things.
Might not actually be a state machine question but it surfaced while playing around with the state machine so it is kind of there I need help I guess
I did a TLDR in the end you can read first if you don’t think you will have to read the whole post since you are awesome and can answer my problem just from that.
So my state machine is fairly straight froward:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// State Machine
/// </summary>
public class StateMachine
{
IState currentState;
public void ChangeState(IState newState)
{
if(currentState != null)
{
currentState.Exit();
}
currentState = newState;
currentState.Enter();
}
public void Update()
{
if(currentState != null)
{
currentState.HandleInput();
currentState.LogicUpdate();
}
}
public void FixedUpdate()
{
if(currentState != null)
{
currentState.PhysicsUpdate();
}
}
}
And the state interface:
/// <summary>
/// Interface handling state
/// </summary>
public interface IState
{
void Enter();
void HandleInput();
void LogicUpdate();
void PhysicsUpdate();
void Exit();
}
Then on my game object I have a “manager” script which ties state machine to the game object (as well as handles other data for the GO) and creates and initializes the first state. I started with a “slimemanager” (an enemy in the game):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SlimeManager : MonoBehaviour
{
protected StateMachine SlimeStateMachine;
public SlimeMovingState MovementState;
public SlimeIdleState IdleState;
private void Start()
{
SlimeStateMachine = new StateMachine();
IdleState = new SlimeIdleState(this, SlimeStateMachine);
MovementState = new SlimeMovingState(this, SlimeStateMachine);
SlimeStateMachine.ChangeState(IdleState);
}
private void Update()
{
SlimeStateMachine.Update();
}
private void FixedUpdate()
{
SlimeStateMachine.FixedUpdate();
}
And a typical Idlestate:
using UnityEditorInternal;
using UnityEngine;
/// <summary>
/// Slime enemy idle state
/// </summary>
public class SlimeIdleState : IState
{
protected SlimeManager slimeManager;
protected StateMachine stateMachine;
public SlimeIdleState(SlimeManager slimeManager, StateMachine stateMachine)
{
this.slimeManager = slimeManager;
this.stateMachine = stateMachine;
}
public void Enter()
{
}
public void Exit()
{
}
public void HandleInput()
{
//TESTSWITCH
if(Input.GetKeyDown(KeyCode.K))
{
stateMachine.ChangeState(slimeManager.MovementState);
}
}
public void LogicUpdate()
{
}
public void PhysicsUpdate()
{
}
}
I then started putting logic in the different states but quickly realized that I should probably try to do a general EnemyManager-class (instead of one manager for each enemy type like Slime, Skeleton etc.) that all enemies use. I then wanted to make the states general as well (like all enemies have an IdleState, MovingState and so on). So I moved the logic (in this case movement) code to the manager and then faced the problem of all enemies implementing the same movement behavior.
TLDR:
So, now what I would like to do is for the MovementState to call a general Move() method in EnemyManager on the enemy GO which in turn I could attach different movement behaviour scripts, which would be called from the MovementState.
End of TLDR
Can’t really use the GetComponent in EnemyManger since there will be a bunch of different movement scripts for different enemies using the same manager, like “JumpingMovement” and “SprintingMovement”, I guess… ?
I tried playing around with having the EnemyManager using a virtual methods to be overriden in the specific movement behavior script, but since the State calls the move method in the base class (EnemyManager), the derived method is not called (unless there is a neat way to do this from the base class which I have not found?)…
I feel like I make this way more complicated than it has to be…
I hope you understand what I mean and there are probably better way to implement what I’m trying to do but this is what I got so far…
I mean if I’m way off in my line of thinking let me know aswell!
Thank you all!
Jonathan