ZombieSurvival GunReload
오늘은 ZombieSurvival 제작에 들어갔다.
그중 내가 가장 이해하기 힘들었던 GunReload 부분을 이해하는 시간을 가져보려 한다.
public bool Reload()
{
if (CurrentState == State.Reloading ||
ammoRemain <= 0 || magAmmo >= gunData.magCapacity)
{
return false;
}
StartCoroutine(Reloading());
return true;
}
private IEnumerator Reloading() // 코루틴을 사용하여 재장전 과정을 처리
{
CurrentState = State.Reloading; // 재장전 상태로 변경
gunAudioPlayer.PlayOneShot(gunData.reloadClip); // 재장전 사운드 재생
yield return new WaitForSeconds(gunData.reloadTime); // 재장전 시간만큼 대기
int ammoRoad = gunData.magCapacity - magAmmo; // 필요한 탄약 수 계산
if (ammoRemain < ammoRoad) // 남은 탄약이 필요한 탄약보다 적으면
{
ammoRoad = ammoRemain; // 남은 탄약 수로 조정
}
magAmmo += ammoRoad; // 탄창에 탄약 추가
ammoRemain -= ammoRoad; // 남은 탄약 수 감소
uiManager.SetAmmoText(magAmmo, ammoRemain); // UI 업데이트
CurrentState = State.Ready; // 재장전 완료 후 상태를 준비 상태로 변경
}
이번에 처음으로 IEnumerator 라는 코루틴(Coroutine)을 사용해 작업을 여러 단계로 나누어 실행할 때 사용하는 것이 나왔다.
쉽게 설명하자면 일반적인 함수는 실행을 마칠 때까지 진행하지만, 코루틴은 중간에 잠시 멈췄다가 나중에 이어서 실행할 수 있다는 차이가 있다.
1.Reload()와 Reloading()의 차이
먼저 두 함수의 역할을 구분할 필요가 있다.
Reload()는 재장전이 가능한 상태인지 확인하고, 가능하다면 재장전을 시작하는 역할을 한다.
if (CurrentState == State.Reloading ||
ammoRemain <= 0 || magAmmo >= gunData.magCapacity)
{
return false;
}
위 조건문에서는 세 가지 상황을 확인한다.
- 이미 재장전 중인 경우
- 남은 탄약이 없는 경우
- 탄창에 탄약이 이미 가득 찬 경우
이 중 하나라도 해당하면 false를 반환하여 재장전을 시작하지 않는다.
반대로 모든 조건을 통과하면 StartCoroutine(Reloading())을 통해 재장전 코루틴을 실행하고 true를 반환한다.
여기서 Reload()는 재장전을 시작할 수 있는지만 판단할 뿐, 실제로 탄약을 옮기는 작업은 Reloading()에서 처리한다는 점이 중요하다.
2. IEnumerator를 활용한 재장전 과정
CurrentState = State.Reloading;
gunAudioPlayer.PlayOneShot(gunData.reloadClip);
yield return new WaitForSeconds(gunData.reloadTime);
코루틴이 실행되면 먼저 총의 상태를 재장전 중으로 변경하고 재장전 사운드를 재생한다.
그 다음 yield return new WaitForSeconds(gunData.reloadTime)에서 지정된 시간만큼 기다린다.
예를 들어 gunData.reloadTime이 2초라면 재장전을 시작한 시점부터 2초가 지난 뒤 다음 코드가 실행된다.
이때 게임 전체가 멈추는 것은 아니다. 재장전 코루틴만 대기하며 다른 게임 동작은 계속 진행된다.
3. 필요한 탄약 수 계산하기
int ammoRoad = gunData.magCapacity - magAmmo;
ammoRoad는 탄창을 가득 채우기 위해 필요한 탄약 수를 의미한다.
예를 들어 탄창 최대 용량이 25발이고 현재 탄창에 10발이 있다면 다음과 같이 계산된다.
25 - 10 = 15
따라서 탄창을 가득 채우려면 15발이 필요하다.
하지만 남은 탄약이 15발보다 적을 수도 있다. 이때 다음 조건문을 사용한다.
if (ammoRemain < ammoRoad)
{
ammoRoad = ammoRemain;
}
필요한 탄약보다 보유한 탄약이 적다면 실제로 가지고 있는 탄약 수만큼만 재장전하도록 변경하는 것이다.
4. 탄약 이동과 UI 업데이트
magAmmo += ammoRoad;
ammoRemain -= ammoRoad;
uiManager.SetAmmoText(magAmmo, ammoRemain);
CurrentState = State.Ready;
재장전에 필요한 탄약 수가 결정되면 해당 수만큼 탄창에 추가하고, 보유 탄약에서는 같은 수만큼 차감한다.
예를 들어 다음과 같은 상황이라고 가정해 보자.
- 탄창 최대 용량: 25발
- 현재 탄창 탄약: 10발
- 남은 탄약: 80발
탄창을 채우는 데 필요한 탄약은 15발이다.
따라서 재장전이 완료되면 다음과 같이 변경된다.
| 항목 | 재장전 전 | 재장전 후 |
|---|---|---|
탄창 탄약 (magAmmo) | 10 | 25 |
남은 탄약 (ammoRemain) | 80 | 65 |
이후 SetAmmoText()를 통해 화면에 표시되는 탄약 정보를 갱신하고, 총의 상태를 Ready로 변경하여 재장전을 마친다.
이번 코드를 살펴보면서 단순히 탄약을 채우는 기능에도 상태 확인, 시간 대기, 탄약 계산, UI 업데이트가 각각 필요하다는 것을 알게 되었다.
특히 IEnumerator와 yield return을 활용하면 재장전처럼 일정 시간이 필요한 작업을 구현할 수 있다는 점이 인상적이었다.



