⭐ FSM (Finite-State Machine) 이란?
객체가 가질 수 있는 상태(State)를 나누어, 각 상태에 따라 동작할 행동을 정의하는 방법입니다.
FSM의 중요한 핵심은 무조건 하나의 상태만을 가지는 것입니다.
이를 이용해 각 상태에 진입했을 때 실행할 로직, 진입한 후 매 프레임 실행할 로직, 상태에서 벗어날 때 실행할 로직 등을
정의해 각 상태에 따른 조건과 행동을 명확히 파악하고 분리할 수 있다는 장점이 있습니다.
플레이어의 정지, 이동, 공격 등의 상태에 따른 행동을 if-else 문으로 체크한다고 가정해보겠습니다.
처음에 상태가 많이 없을 때는 관리하기 편하고 코드를 짜기 쉽지만 실제 게임을 만들어보면 플레이어 로직은 결코
단순하지 않습니다.
수 많은 상태가 생기게 된다면 if-else 문으로 인한 조건 체크가 굉장히 까다로워지고 코드의 가독성이 안좋아져
추후 리팩토링을 하는 과정에도 문제가 생길 것입니다.
이러한 문제점을 해결하기 위해 상태 패턴 또는 FSM 등을 사용합니다.
FSM 예시
아주 간단한 예시를 들어보겠습니다.
정지, 이동, 공격, 이동하면서 공격의 상태를 만들어 플레이어의 클래스에서 관리하는 예제입니다.
● IState 인터페이스
public interface IState
{
//상태에 진입했을 때 실행
public void OnStateEnter();
//상태에 진입 후 매 프레임 실행
public void OnStateUpdate();
//상태에서 벗어날 때 실행
public void OnStateExit();
}
● 각각의 상태들이 가질 기본적인 상태 인터페이스
● 상태에 진입, 진입 후 매 프레임, 벗어날 때 호출할 메서드를 미리 구현
● Idle, Walk, Attack, WalkAttack
//Idle
public class IdleState : IState
{
public void OnStateEnter()
{
Debug.Log("Idle 진입");
}
public void OnStateExit()
{
Debug.Log("Idle 진행중");
}
public void OnStateUpdate()
{
Debug.Log("Idle 탈출");
}
}
//Walk
public class WalkState : IState
{
public void OnStateEnter()
{
Debug.Log("Walk 진입");
}
public void OnStateExit()
{
Debug.Log("Walk 진행중");
}
public void OnStateUpdate()
{
Debug.Log("Walk 탈출");
}
}
//Attack
public class AttackState : IState
{
public void OnStateEnter()
{
Debug.Log("Attack 진입");
}
public void OnStateExit()
{
Debug.Log("Attack 진행중");
}
public void OnStateUpdate()
{
Debug.Log("Attack 탈출");
}
}
//WalkAttack
public class WalkAttackState : IState
{
public void OnStateEnter()
{
Debug.Log("WalkAttack 진입");
}
public void OnStateExit()
{
Debug.Log("WalkAttack 진행중");
}
public void OnStateUpdate()
{
Debug.Log("WalkAttack 탈출");
}
}
● 필요한 상태들의 클래스를 만들어 IState를 상속받은 후 각 로직들을 구현하면 됩니다.
● 걸어가면서 공격 등의 두 가지 상태가 포함되어야 하는 경우 걸어가면서 공격하는 새로운 상태를 만드는 것이 깔끔합니다.
● Player
public class Player : MonoBehaviour
{
private IState playerState;
private void Update()
{
//Update 문에서 현재 상태의 Update 호출
playerState?.OnStateUpdate();
}
public void ChangeState(IState state)
{
//이미 상태가 있다면 벗어날 때 로직 호출
playerState?.OnStateExit();
//상태 변경
playerState = state;
//새로운 상태에 진입했을 때 로직 호출
playerState.OnStateEnter();
}
}
● 필드에 플레이어 상태를 뜻하는 IState 변수를 가지고 있습니다.
● 상태를 변경하는 ChangeState 메서드가 있습니다.
○ 이전의 상태가 있다면 OnStateExit() 메서드를 호출하여 벗어날 때 로직을 수행
○ 새로운 상태가 변경되면 OnStateEnter() 메서드를 호출하여 진입할 때 로직을 수행
● 현재 상태가 매 프레임 실행할 OnStateUpdate() 메서드를 Update 문에서 수행
FSM의 장점과 단점
● 장점
○ 상태별로 수행해야 할 로직이 분리되어 있어 구조가 명확합니다.
○ 상태가 직관적이고 이해하기 쉽습니다.
○ 버그가 적어지고 디버깅이 쉽습니다.
○ 한 객체의 상태 규모가 적을 때 유용합니다.
● 단점
○ 상태가 많아질 경우 점점 복잡해집니다.
○ 중복되는 코드가 생길 수 있습니다.
○ 상태 전환 규칙 코드로 인해 복잡해질 수 있습니다.
○ 2개 이상의 복합적인 상태가 필요할 경우 새로운 상태로 만들어줘야합니다.
● 그럼 복잡한 상태의 구현은 어떻게?
FSM에서 한단계 더 보강된 방식인 HFSM(Hierachical Finite State Machine) 또는 Behavior Tree(행동 트리) 등의
새로운 패턴을 사용합니다.
⭐ HFSM (Hierachical Finite State Machine) 계층적 유한 상태 기계
말 그대로 유한 상태 기계를 계층적인 구조로 만든 방식입니다.
기존의 FSM의 경우에는 모든 상태가 동등한 관계를 이루고 있었지만
HFSM의 경우에는 공통된 사항끼리 묶어 계층적인 구조를 띕니다.
예를 들어 FSM에서는 Idle, Walk, Attack이 동등한 계층이었지만
HFSM에서는 이동 관련 → Idle, Walk / 공격 관련 → Attack, PowerAttack 등으로 나누어 관리합니다.
[MoveState] ← 상위 상태(공통 로직: 속도, 물리 이동 등)
→ Idle State ← 하위 상태
→ walk State
[AttackState]
→ Attack State
→ PowerAttack State
'개발, IT > 디자인 패턴 & 알고리즘' 카테고리의 다른 글
| [알고리즘] A* 알고리즘 (에이스타 알고리즘) (1) | 2025.11.21 |
|---|---|
| [알고리즘] 다익스트라 알고리즘 (Dijkstra Algorithm) (0) | 2025.11.20 |
| [디자인 패턴] MVC, MVP, MVVM 패턴 (0) | 2025.11.12 |
| [디자인 패턴] 옵저버 패턴 (Observer Pattern) (0) | 2025.10.22 |
| [디자인 패턴] 어댑터 패턴 (Adapter Pattern) (0) | 2025.10.21 |