State 패턴?
- 객체 내부의 상태가 변경될 때 해당 객체가 그의 행동을 변경할 수 있도록 하는 행동 디자인 패턴
- 캐릭터는 끊임없이 상태가 전환됨
- 캡슐화가 잘 되어있음
- FSM과 유사하나, 상태패턴을 공부한 뒤, FSM을 사용할 것
기본 예시
public class PlayerController : MonoBehaviour
{
public enum PlayerState
{
Die,
Moving,
Idle
}
PlayerState _state = PlayerState.Idle;
void UpdateDie()
{
// ... 실행 로작 ...
}
void UpdateMoving()
{
// ... 실행 로직 ...
}
void UpdateIdle()
{
// ... 실행 로직 ...
}
void Update()
{
switch (_state)
{
case PlayerState.Die:
UpdateDie();
break;
case PlayerState.Moving:
UpdateMoving();
break;
case PlayerState.Idle:
UpdateIdle();
break;
}
}
}
가장 기본적인 예시, Interface를 사용하는 것이 일반적임.
적 구현 심화 예시
- IState : 구체적인 상태 클래스로 연결할 수 있도록 설정
- Context : 클라이언트가 객체의 내부 상태를 변경할 수 있도록 요청하는 인터페이스를 정의
스크립트
IEnemyState
public interface IEnemyState
{
void Handle(EnemyController controller);
}
EnemyStateContext
public class EnemyStateContext
{
public IEnemyState CurrentState
{
get; set;
}
private readonly EnemyController _enemyController;
public EnemyStateContext(EnemyController enemyController)
{
_enemyController = enemyController;
}
public void Transition()
{
CurrentState.Handle(_enemyController);
}
public void Transition(IEnemyState state)
{
CurrentState = state;
CurrentState.Handle(_enemyController);
}
}
EnemyController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyController : MonoBehaviour
{
public EnemyStateContext _enemyStateContext { get; private set; }
private IEnemyState _idleState;
private IEnemyState _chasingState;
private IEnemyState _walkState;
private IEnemyState _attackState;
private void Start()
{
_enemyStateContext = new EnemyStateContext(this);
_idleState = gameObject.AddComponent<EnemyIdleState>();
_chasingState = gameObject.AddComponent<EnemyChaisngState>();
_walkState = gameObject.AddComponent<EnemyWalkState>();
_attackState = gameObject.AddComponent<EnemyAttackState>();
_enemyStateContext.Transition(_idleState);
}
public void IdleStart()
{
_enemyStateContext.Transition(_idleState);
}
public void ChasingStart()
{
_enemyStateContext.Transition(_chasingState);
}
public void WalkStart()
{
_enemyStateContext.Transition(_walkState);
}
public void AttackStart()
{
_enemyStateContext.Transition(_attackState);
}
}
EnemyIdleState
using System.Collections;
using UnityEngine;
public class EnemyIdleState : MonoBehaviour, IEnemyState
{
private EnemyController _enemyController;
private float _idleTime;
private float _time;
// Start문과 동일하게 사용
public void Handle(EnemyController enemyController)
{
if (!_enemyController)
_enemyController = enemyController;
Debug.Log("Idle 상태 시작");
_idleTime = Random.Range(_enemyController.EnemySO.MinIdleTime, _enemyController.EnemySO.MaxIdleTime);
_time = 0;
StartCoroutine(COUpdate());
}
// Update문과 동일하게 사용
IEnumerator COUpdate()
{
while (true)
{
// 각각의 상태 변환 조건 설정
if (_enemyController.Distance <= _enemyController.EnemySO.SwordAttackRange)
{
_enemyController.AttackStart();
break;
}
if (_time >= _idleTime)
{
_enemyController.WalkStart();
break;
}
yield return null;
}
}
}
'C#' 카테고리의 다른 글
문자열로 된 수식 계산 (0) | 2024.07.23 |
---|---|
10진수를 2진수, 8진수, 16진수로 변환 (0) | 2024.02.15 |
제곱근 구하기 (Math.Sqrt) (0) | 2023.12.18 |
절대값 구하기 (1) | 2023.12.06 |
삼각함수 (0) | 2023.12.04 |