TIL 0312 최종 프로젝트 - 3 / 잡몹 FSM 구조 및 베이스 코드

강성원·2024년 3월 24일
0

TIL 오늘 배운 것

목록 보기
49/70
post-thumbnail

잡몹 FSM 구조

새로 공부한 FSM구조를 기반으로 FSM을 간단히 만들어보았다.

Root 상태, Sub 상태, Sub의 Sub 상태가 있다.

  • 모든 계층의 상태는 Sub상태 혹은 Super상태를 가질 수 있다.
  • 위 사진에서는 Alive상태의 Sub가 Ground상태이다.
  • Ground의 Super가 ALive이고, Ground의 Sub상태들은 Chasing, Standoff, Run이다.
  • Chasing, Standoff, Run의 Super 상태가 Ground이다.

밑에서 코드로 설명하겠지만 이 FSM의 특징은 한 프레임에 모든 계층의 현재 상태를 전부 Update 하는 것이다.
Alive, Ground, Chasing은 각자 따로 존재하는 상태이며 관계만 연결돼있을 뿐이다.

기존에 내배캠 강의에서 배운 FSM은 Alive나 Ground를 상속받아서 Chasing 상태를 구현했다는 것에서 차이가 있다.

새로운 방식은 Super 상태의 변환을 체크해서 상위 상태의 변환 조건을 체크하거나 변환하는 것에 좀 더 직관적이다.

현재 Alive-Ground-Chasing인 상태에서 Root상태인 Alive가 Dead 상태로 바뀌면 그 때부터 Dead와 이어진 상태들을 업데이트 하기 시작한다.

FSM 베이스 코드

베이스 코드를 다른 상태 클래스에서 상속 받아서 사용한다.

상태 업데이트

public void UpdateStates() 
{
    UpdateState();
    if (_currentSubState != null)
        _currentSubState.UpdateStates();
}

현재 모든 계층의 선택된 상태를 업데이트 하는 방법은 간단하다.
현재 상태의 Sub상태가 존재한다면 그것도 업데이트 해주면 된다.

상태 변환

상태 업데이트 중에 다른 상태로의 변환 조건이 충족되면 다른 상태로 변환한다.

protected void SwitchState(EnemyBaseState newState) 
{ 
    ExitState();

    newState.EnterState();

    if(_isRootState)
    {
        _ctx.CurrentState = newState;
    }
    else if(_currentSuperState != null)
    {
        _currentSuperState.SetSubState(newState);
    }
}

BaseState 전체 코드

public abstract class EnemyBaseState
{
    protected bool _isRootState = false;
    protected EnemyStateMachine _ctx;
    protected EnemyStateFactory _factory;
    protected EnemyBaseState _currentSuperState;
    protected EnemyBaseState _currentSubState;

    public EnemyBaseState(EnemyStateMachine currentContext, EnemyStateFactory enemyStateFactory)
    {
        _ctx = currentContext;
        _factory = enemyStateFactory;
    }


    public abstract void EnterState();
    public abstract void UpdateState();
    public abstract void ExitState();
    public abstract void CheckSwitchStates(); // 상태 나타내는 bool변수 두고 어떤 상태로 바꿀지 결정
    public abstract void InitializeSubState();
    public void UpdateStates() 
    {
        UpdateState();
        if (_currentSubState != null)
            _currentSubState.UpdateStates();
    }

    public void ExitStates() // 보류
    {
        ExitState();
        if (_currentSubState != null)
            _currentSubState.ExitStates();
    }

    protected void SwitchState(EnemyBaseState newState) 
    { 
        ExitState();

        newState.EnterState();

        if(_isRootState)
        {
            _ctx.CurrentState = newState;
        }
        else if(_currentSuperState != null)
        {
            _currentSuperState.SetSubState(newState);
        }
    }

    public void SetSuperState(EnemyBaseState newSuperState) 
    {
        _currentSuperState = newSuperState;
    }   
    public void SetSubState(EnemyBaseState newSubState) 
    { 
        _currentSubState = newSubState;
        newSubState.SetSuperState(this);
    }
}
profile
개발은삼순이발

0개의 댓글