Unity - FSM(Finite State Machine)(1)

2024. 6. 17. 21:19Unity/Unity 학습정리

FSM 유한상태머신이다. 유한한 여러 상태가 존재하는데 여러 상태중 한 개의 상태만 가질 수 있고 상황 혹은 유저의 인풋 여러 요인으로 상태가 변화하는 것을 관리해주는 디자인 패턴이다. 구조적으로 잘 구성되어있고 애니메이션도 상태에 따라서 넣어 줄 수 있으며, 상당히 복잡한 행동을 하는 객체가 아니면 매우 유용하다.


 


FSM 구조

FSM은 디자인 패턴이기 때문에 구조 자체는 여러 구조로 나타낼 수 있다. 가장 간단한 구조가 Switch문을 이용해 구현하는 것이다.

public enum State
{
	Idle,
    Run,
    Walk
}

switch(State)
{
	case(Idle): Debug.Log("가만히 있다");
    case(Run): Debug.Log("달린다");
    case(Walk): Debug.Log("걷다");
}

구조가 간단한 만큼 확장성에서 떨어진다. 매번 Switch문을 참조해야하고 Idle에서 하던 행위를 취소하고 다른 행위로 넘어가야 할 때도 써야하는 코드가 길어지고 가독성에서도 불편할 것이다.

 

다음은 StateMachine을 이용해서 구현하는 방식이다.

public interface IState
{
    public void Enter();
    public void Exit();
    public void Update();
    public void PhysicsUpdate();  
}
public abstract class StateMachine
{
    protected IState currentState;

    public void ChangeState(IState state)
    {
        currentState?.Exit();
        currentState = state;
        currentState?.Enter();
    }

    public void Update()
    {
        currentState?.Update();
    }

    public void PhysicsUpdate()
    {
        currentState?.PhysicsUpdate();
    }
}

 

 

위 StateMachine은 세 가지의 일을 한다.

  • State가 바뀔때마다 기존 상태에서 Exit() 새로운 상태를 Enter()하면서 이전 상태를 완전히 초기화하고 새로운 상태를 넣는다.
  • Update를 통해 현재 상태에서 해야하는 Update만 Update를 해준다.
  • PhysicsUpdate도 마찬가지이다.
public class PlayerBaseState : IState
{
    protected PlayerStateMachine stateMachine;
    protected PlayerData playerData;

    public PlayerBaseState(PlayerStateMachine stateMachine)
    {
        this.stateMachine = stateMachine;
        playerData = stateMachine.player.data.PlayerData;
    }
    public virtual void Enter()
    {
    }

    public virtual void Exit()
    {
    }

    public virtual void Update()
    {
    }

    public virtual void PhysicsUpdate()
    {
    }
}

IState를 상속받는 PlayerBaseState는 뼈대를 만들수 있다.

Enter(),Exit(),Update(),PhysicsUpdate(), 여기서 물론 업데이트 문은 Monobehaviour에서 가져온 속성이 아니기 때문에 인 게임에서 프레임당 수행하는 함수들은 아니다. 대신 해당 업데이트 구문들은 모두 StateMachine에서 부르고 해당 StateMachin을 사용하는 MonoBehaviour를 상속받는 객채에서 불러서 사용한다.

public class PlayerIdleState : PlayerBaseState
{
    public PlayerIdleState(PlayerStateMachine stateMachine) : base(stateMachine)
    {
    }

    public override void Enter()
    {
        stateMachine.movementSpeedModifier = 0f;
        base.Enter();
        Debug.Log("IdleMode");
        StartAnimation(stateMachine.player.AnimationData.idleParameterHash);
    }

    public override void Exit()
    {
        base.Exit();
        Debug.Log("idleOut");
        StopAnimation(stateMachine.player.AnimationData.idleParameterHash);

    }

    public override void Update()
    {
        base.Update();
        if(IsInChasinginRange())
        {
            stateMachine.ChangeState(stateMachine.chasingState);
        }
    }

    public override void PhysicsUpdate()
    {
        base.PhysicsUpdate();
    }
}

그리고 PlayerBaseState를 상속받은 여러 State중 하나인 IdleState이다. 해당 State에서 상속받은 함수들을 모두 해당 State에서 원하는 동작을하게 수정을 해준다.

 

다음 포스팅에서는 Animation과의 연계에 대해서 포스팅할 예정이다.

 

 

'Unity > Unity 학습정리' 카테고리의 다른 글

Unity - FSM(Finite State Machine)(3)  (0) 2024.06.20
Unity - FSM(Finite State Machine)(2)  (0) 2024.06.18
Unity - 슬라이더바로 사운드 조절하기  (1) 2024.06.05
Unity - Scriptable Object  (0) 2024.05.27
Unity - Object Pool  (0) 2024.05.23