Update 사용 없이 Coroutine으로 게임 진행 구현Unity/Study2024. 6. 14. 19:15
Table of Contents
기술 소개
유니티를 Monobehaviour 클래스에 생명주기(Life Cycle) 중에 가장 많이 쓰이는 Update 클래스가 존재한다.
Update 클래스는 프레임 당 한번 호출되는 클래스로 프레임 업데이트를 위한 주요 작업 함수이다.
해당 클래스를 잘 제어하지 못하고 Update 클래스에 의존만 한다면 프레임 드롭같이 최적화 문제가 발생할 수도 있다.
그래서 P.P.R 프로젝트에서 전반적인 게임 플레이를 Update 사용 없이 Coroutine으로 진행 루틴을 만들려고 한다.
기술 설명
YieldCache.cs : 코루틴 최적화
/// Boxing 발생하지 않게 해주며, 의도치 않게 가비지가 생성되는 것을 방지
class FloatComparer : IEqualityComparer<float>
{
bool IEqualityComparer<float>.Equals(float x, float y)
{
return x == y;
}
int IEqualityComparer<float>.GetHashCode(float obj)
{
return obj.GetHashCode();
}
}
private static readonly Dictionary<float, WaitForSeconds> _timeInterval = new();
// 코루틴 Yield WaitForSeconds 최적화
public static WaitForSeconds WaitForSeconds(float seconds)
{
if (!_timeInterval.TryGetValue(seconds, out WaitForSeconds waitForSeconds))
_timeInterval.Add(seconds, waitForSeconds = new WaitForSeconds(seconds));
return waitForSeconds;
}
- 코루틴을 사용할 때 new 키워드 사용으로 GC 비용이 발생
- 게임 제작 특성상, 코루틴 만으로 진행 루틴을 만들어야 하니 많은 new 사용으로 GC 부하가 예상됨
- 그래서 코루틴을 미리 캐싱하여 불필요한 인스턴스 생성을 방지한다
- 참고 자료
BattleSystem.cs : 전투 시작
// 코루틴 Start로 턴 제어
private IEnumerator Start()
{
// 전투 세팅
this.gameBoard.SetBoard();
yield return YieldCache.WaitForSeconds(1.0f);
// 전투 시작 (반복)
while (true)
{
// 플레이어 행동 턴
yield return StartCoroutine(PlayerTurn());
// 적 행동 턴
yield return StartCoroutine(EnemyTurn());
}
}
- Start 클래스를 열거자 IEnumrator로 선언하여 코루틴을 사용할 준비를 한다
- 게임 시작 전 전투 세팅을 한번 호출하고 1초의 딜레이 후 전투 시작
- yield return StartCoroutine을 통해 다른 코루틴이 끝날 때까지 대기하여 플레이어 턴이 끝나고 적 턴이 진행하도록 한다
BattleSystem.cs : 전투 진행
// 플레이어 턴
private IEnumerator PlayerTurn()
{
if (this.battlePlayer.OnStart)
{
yield return StartCoroutine(this.battlePlayer.PlayerOnStart());
}
else
{
this.battlePlayer.PlayerOnInit();
}
yield return StartCoroutine(BattleNotice.Instance.UpdateNotice("Player Turn"));
// 적 스킬 생성
foreach (var battleEnemy in this.BattleEnemys)
{
battleEnemy.EnemySkillInstance(this.gameBoard);
}
// 플레이어 행동 반복
// 최소한 2의 행동을 소모해야 작동 => 행동력이 1 이하일 경우 턴 종료
while (this.battlePlayer.CurrentACT > 1)
{
// 플레이어 card 선택
yield return this.gameBoard.WaitForSelection();
// 최종 선택된 cards 소멸
yield return this.gameBoard.DespawnSelection();
// 빈 곳으로 cards 이동
yield return this.gameBoard.WaitForMovement();
// 소멸 된 cards 수 만큼 재생성
yield return this.gameBoard.RespawnCards();
// 행동 끝난 후 적 상태 체크
EnemyStateCheck();
}
}
// 적 턴
public IEnumerator EnemyTurn()
{
// 적 행동 초기화
foreach (var battleEnemy in this.BattleEnemys)
{
battleEnemy.Init();
}
yield return StartCoroutine(BattleNotice.Instance.UpdateNotice("Enemy Turn"));
// 적 스킬 사용
foreach (var battleEnemy in this.BattleEnemys)
{
yield return StartCoroutine(battleEnemy.EnemyUseSkill());
}
}
- PlayerTurn안의 while 반복문을 통해 코루틴을 순서대로 불러서 행동 루틴을 구현하였다
- EnemyTurn도 적의 상태에 따라 스킬이 사용되도록 AI 패턴을 호출한다
구현 결과
'Unity > Study' 카테고리의 다른 글
유니티 C# 코드 컨벤션 (0) | 2024.06.15 |
---|---|
유니티 실시간 딜레이 계산 (0) | 2024.01.24 |
유니티 로그라이크 방 타입에 맞는 오브젝트 생성 (0) | 2023.12.21 |
유니티 로그라이크 다음 방으로 이동 (0) | 2023.12.19 |
유니티 로그라이크 문으로 방 연결하기 (0) | 2023.12.18 |