2024. 3. 13. 13:52ㆍ유니티 공부
유한 상태 기계 (FSM)
유한 상태 기계 패턴은 State패턴을 이용한 더 심화된 개념으로
주어지는 모든 시간에서 처해 있을 수 있는 유한 개의 상태를 가지고 주어지는 입력에 따라 어떤 상태에서 다른 상태로 전환시키거나 출력이나 액션이 일어나게 하는 장치 또는 그런 장치를 나타낸 모델
유한 상태 기계 바탕에 깔린 아이디어는 객채의 행동을 쉽게 처리할 수 있는 클래스 또는 상태들로 분해 하는것
(출처 유튜브 고박사의 유니티 노트)
현재 AI 적 몬스터 행동 패턴이다.
이런식으로 스위치문 또는 if문으로 하면 제약 사항들이 많아질테고 만약에 행동 패턴이 많아지면 확장할때 그리고 수정할때 직관적이지 않아 쉽게 설계하지 못할것이고 스위치문 if문의 조건들이 많아지면 미세하게 처리 속도가 느려질수도 있다.
그래서 쓰는게 유한 상태 기계이다.
유한 상태 기계의 장점을 소개하겠다.
1. 행동들을 덩어리(클래스)로 분리되기 때문에 오류가 났을때 어떤 상태에서 오류가 나는지 쉽게 알수 있고
오류 수정이 용이하다
2. 아까도 말했듯이 덩어리로 만들면서 본질적으로 코드화된 규칙들을 따르기 때문에 처리속도가 빠르다.
3. 직관적이다.
4. 새로운 상태나 이벤트를 만들기가 쉽다.
현재 프로젝트에서 내가 만든 상태머신을 보여주겠다.
일단 스테이트 클래스 (인터페이스)는 Action 대리자를 이용해 몬스터 플레이어만이 아닌 아이템 등등에서도 사용할수있게 더욱 확장되어 만들었다.
이렇게하면 굳이 MoveState 같이 클래스들을 안만들고 State패턴을 담은 dictionary에 행동 상태들을 추가하고 행동 상태를 바꿀때마다 교체하게 만들었다.
public class State
{
//상태를 확인하고 상태를 호출시켜주는 대리자 변수들
Action _enterAction;
Action _stayAction;
Action _fixedStayAction;
Action _exitAction;
//처음에 객체 생성을 할때 위에있는 Action 상태들을 할당하기 위해 파라미터를 넣어줌
public State(Action enterAction, Action fixedStayAction, Action stayAction, Action exitAction)
{
_enterAction = enterAction;
_fixedStayAction = fixedStayAction;
_stayAction = stayAction;
_exitAction = exitAction;
}
/// <summary>
/// 이 클래스에 들어왔을때 한번 호출
/// </summary>
public virtual void Enter()
{
_enterAction?.Invoke();
}
/// <summary>
/// Fixed프레임 마다 호출
/// </summary>
public virtual void FixedStay()
{
_fixedStayAction?.Invoke();
}
/// <summary>
/// 프레임마다 호출
/// </summary>
public virtual void Stay()
{
_stayAction?.Invoke();
}
/// <summary>
/// 이 클래스에서 나왔을때 한번 호출
/// </summary>
public virtual void Exit()
{
_exitAction?.Invoke();
}
}
현재 상태들을 작동시키는 스테이트머신이다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StateMachine
{
private State currentState; // 현재 상태
private State previousState; // 이전 상태
//처음에 스테이트머신을 생성 할때 자기자신과 딕셔너리,배열,리스트에 인덱스에 넣어놨던 처음에 실행해야하는 상태를 넣고 호출
public void Setup(State entryState)
{
currentState = null;
previousState = null;
ChangeState(entryState);
}
//Stay와 FixedStay는 유니티에서 지원하는 Update,FixedUpdate에 연결해야함
public void FixedStay()
{
if (currentState != null)
{
currentState.FixedStay();
}
}
public void Stay()
{
if (currentState != null)
{
currentState.Stay();
}
}
//ChangeState 함수는 딕셔너리,배열,리스트에서 객체를 생성하고 저장했던 State<T>클래스를 가져와서
//그 인덱스에 할당되있었던 State<T> Enter,Exit를 호출하고 Stay,FixedStay를 프레임마다 호출
public void ChangeState(State newState)
{
if (newState == null)
{
return;
}
if (currentState != null)
{
previousState = currentState;
currentState.Exit();
}
currentState = newState;
currentState.Enter();
}
//아이템만 쓸경우
public void EnterState(State newState)
{
if (newState == null)
{
return;
}
currentState = newState;
currentState.Enter();
}
//상태를 체인지 하지말고 Exit만 발동하고 싶을때?
public void ExitState()
{
currentState.Exit();
currentState = null;
}
//ReversState는 ChangeState에서 previousState변수에 저장됬었던 이전상태를 다시 전환하고 싶을때 호출하면됌
public void ReversState()
{
ChangeState(previousState);
}
}
이런식으로 열거형을 int형으로 바꾸고 생성자 Action매개변수에 현재 작동해야되는 키워드들을 넣고 ChangeState 할때 작동되게 하는 방식 빈칸들은 Action 대리자이기 때문에 빈칸으로 냅두면 알아서 호출을 안할테니 상관없다.
이런식으로 장비에서도 사용하는 모습을 볼수있다.
'유니티 공부' 카테고리의 다른 글
New InputSystem (2) (0) | 2024.03.24 |
---|---|
New InputSystem (1) (0) | 2024.03.24 |
프리팹을 생성하고 쓸때 주의할점 (GetComponent를 쓰는이유) (1) | 2023.11.23 |