Hello everyone, it’s my first time posting here.
I’m working on a simple 2D fighting game, so I have multiple characters with different moves and abilities.
Before I used a type of state machine using Enum, but now I’m trying to implement a finite state machine that uses multiple scripts, I have a StateMachine script that takes care of changing state and everything else, a MovementSM script that inherits (?) from StateMachine and sets up all the states, and the Moving and Idle states.
StateMachine
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StateMachine : MonoBehaviour
{
protected BaseState currentState;
public string characterName;
public float atk, def, speed, fric;
public float currentSpeed, topSpeed;
public Vector3 m_Velocity = Vector3.zero;
public Rigidbody2D rb;
public Controls controls;
public Vector2 movement;
private void OnEnable()
{
controls.Enable();
}
private void OnDisable()
{
controls.Disable();
}
void Start()
{
currentState = GetInitialState();
if (currentState != null)
currentState.Enter();
}
void Update()
{
if (currentState != null)
currentState.Update();
}
void FixedUpdate()
{
Vector3 targetVelocity = new Vector2(MoveInput() * speed, rb.velocity.y);
rb.velocity = Vector3.SmoothDamp(rb.velocity, targetVelocity, ref m_Velocity, fric);
if (currentState != null)
currentState.FixedUpdate();
}
public void ChangeState(BaseState newState)
{
currentState.Exit();
currentState = newState;
currentState.Enter();
}
protected virtual BaseState GetInitialState()
{
return null;
}
public float MoveInput()
{
movement = new Vector2(controls.Gameplay.Move.ReadValue<Vector2>().x, controls.Gameplay.Move.ReadValue<Vector2>().y);
return movement.x;
}
private void OnGUI()
{
string state = currentState != null ? currentState.name : "no current state";
string content = characterName + ": " + atk + " - " + def + " - " + speed + " - " + state;
GUILayout.Label($"<color='black'><size=40>{content}</size></color>");
}
}
MovementSM
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovementSM : StateMachine
{
public Idle idleState;
public Moving movingState;
public PlayableCharacter playableCharacter;
private void Awake()
{
idleState = new Idle(this);
movingState = new Moving(this);
characterName = playableCharacter != null ? playableCharacter.charName : "no object attached";
atk = playableCharacter != null ? playableCharacter.charAtk : 0;
def = playableCharacter != null ? playableCharacter.charDef : 0;
speed = playableCharacter != null ? playableCharacter.charSpeed : 0;
fric = playableCharacter != null ? playableCharacter.charFric : 0;
controls = new Controls();
}
protected override BaseState GetInitialState()
{
return idleState;
}
}
Idle State
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Idle : BaseState
{
public Idle(MovementSM stateMachine) : base("Idle", stateMachine) { }
public override void Enter()
{
base.Enter();
stateMachine.topSpeed = 0;
}
public override void Update()
{
base.Update();
if (Mathf.Abs(stateMachine.MoveInput()) >= Mathf.Epsilon)
stateMachine.ChangeState(((MovementSM)stateMachine).movingState);
}
}
Moving State
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Moving : BaseState
{
public Moving(MovementSM stateMachine) : base("Moving", stateMachine) { }
public override void Enter()
{
base.Enter();
stateMachine.topSpeed = stateMachine.speed;
}
public override void Update()
{
base.Update();
if (Mathf.Abs(stateMachine.MoveInput()) < Mathf.Epsilon)
stateMachine.ChangeState(((MovementSM)stateMachine).idleState);
}
}
As you can see to initialize a state I refer to the name of the class (Idle, Movement, etc.), and to change state I refer to the MovementSM class.
So now my question would be, how do I implement both “general” states that will be the same for every character like these ones, and specific states for each character that represent their abilities and attacks?
I ask this because I don’t think making the same state for each character would be wise, but I also don’t know how can I tell, for example, the Idle state to call the attack state of a specific character when the attack button is pressed.
The solution may be very simple and I’m being really dumb, but I’m trying to learn more advanced programming skills so bear with me
.