새로 공부한 FSM구조를 기반으로 FSM을 간단히 만들어보았다.
Root 상태, Sub 상태, Sub의 Sub 상태가 있다.
밑에서 코드로 설명하겠지만 이 FSM의 특징은 한 프레임에 모든 계층의 현재 상태를 전부 Update 하는 것이다.
Alive, Ground, Chasing은 각자 따로 존재하는 상태이며 관계만 연결돼있을 뿐이다.
기존에 내배캠 강의에서 배운 FSM은 Alive나 Ground를 상속받아서 Chasing 상태를 구현했다는 것에서 차이가 있다.
새로운 방식은 Super 상태의 변환을 체크해서 상위 상태의 변환 조건을 체크하거나 변환하는 것에 좀 더 직관적이다.
현재 Alive-Ground-Chasing인 상태에서 Root상태인 Alive가 Dead 상태로 바뀌면 그 때부터 Dead와 이어진 상태들을 업데이트 하기 시작한다.
베이스 코드를 다른 상태 클래스에서 상속 받아서 사용한다.
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);
}
}
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);
}
}