// 문제 코드
public enum StateList
{
Idle, Move, Jump, Attack
}
public class PlayerState : MonoBehaviour
{
private int _direction;
[SerializeField] private StateList CurrentState;
private void Update()
{
// 키 입력 에 따른 각 상태 변화
}
private void Idle()
{
// 기능 로직
// 애니메이션 변화 로직
// 예외처리 등
}
private void Move()
{
// 기능 로직
// 애니메이션 변화 로직
// 예외처리 등
}
private void Jump()
{
// 기능 로직
// 애니메이션 변화 로직
// 예외처리 등
}
private void Attack()
{
// 기능 로직
// 애니메이션 변화 로직
// 예외처리 등
}
}
// 문제 코드
void Update()
{
HandleInput();
ApplyGravity();
CheckGround();
if (_state == PlayerState.Idle)
{
...
}
else if (_state == PlayerState.Move)
{
...
}
else if (_state == PlayerState.Jump)
{
...
if (CanDoubleJump()) ...
if (InputDash()) ...
if (InputAttack()) ...
if (IsHit()) ...
}
else if (_state == PlayerState.AirAttack)
{
...
if (ComboWindowOpen()) ...
if (IsHit()) ...
if (IsGrounded()) ...
}
else if (_state == PlayerState.Hit)
{
...
if (RecoverTimeOver()) ...
}
else if (_state == PlayerState.Die)
{
...
}
// 계속 증가
}
상태(State): 어떤 객체가 특정 상황에서 어떻게 행동해야 하는지를 결정하는 행동 규칙
| 요소 | 책임 | 하면 안 되는 것 |
|---|---|---|
| Context | 상태 실행 | 상태 로직 직접 구현 |
| StateMachine | 상태 교체 | 입력 처리 |
| ConcreteState | 자기 상태 행동 전달 | 다른 상태 내부 접근 |
동작 흐름
User Input -> Player -> StateMachine -> State.Upate()
입력 → 코드 FSM → 물리 → Animator
전환 흐름
CurrentState?.Exit()
↓
NewState.Enter()
using UnityEngine;
// IdleState, MoveState, JumpState, AttackState ....
// 행동 의도만 전달 -> 객체
public interface IState
{
// 가질 주기 3가지
void Enter();
void Update();
void Exit();
}
Enter() -> 상태에 들어올 때 한 번만 실행
Update() -> 상태에 머무르는 동안 매 프레임 실행
Exit() -> 상태를 떠날 때 정리 작업 실행
using UnityEngine;
// 얘가 해야할 책임?
// State를 교체/관리
public class StateMachine
{
IState _currentState;
// 유니티 씬상에 존재하는 "어떤 객체"가 상태(state)를 전환/실행
public void ChangeState(IState state)
{
_currentState?.Exit();
_currentState = state;
_currentState.Enter();
}
// 유니티 이벤트 함수인 Update() 랑 다름..
public void Update()
{
_currentState?.Update();
}
}
using UnityEngine;
// 입력 처리 / 물리 판정 / 애니메이션 결정
public class PlayerController : MonoBehaviour
{
Rigidbody2D _rb;
Animator _animator;
StateMachine _stateMachine;
// Player가 사용할 Stete들
public IdleState Idle {get; private set; }
public MoveState Move { get; private set; }
public JumpState Jump { get; private set; }
void Awake()
{
_stateMachine = new StateMachine();
Idle = new IdleState(this);
Move = new MoveState(this);
Jump = new JumpState(this);
}
void Start()
{
_stateMachine.ChangeState(Idle);
}
void Update()
{
_stateMachine.Update();
}
public void ChangeState(IState state)
{
_stateMachine.ChangeState(state);
}
}
using UnityEngine;
public class IdleState : IState
{
PlayerController _player;
public IdleState(PlayerController player)
{
_player = player;
}
public void Enter()
{
}
public void Update()
{
// Move, Jump
if(_player.MoveInput != 0) // 움직이면
{
_player.ChangeState(_player.Move); // 상태 변환
return;
}
if(_player.IsJumpInput()) // 점프하면
{
_player.ChangeState(_player.Jump); // 상태 변환
}
}
public void Exit()
{
}
}