본문 바로가기
Development/Unity

[내일배움캠프 50일차 TIL] 오브젝트 풀 객체 초기화

by 식냥 2024. 6. 26.
728x90

 

[ 트러블 슈팅 ]

적이 죽고 리스폰되지 않음

적을 구현할 때 오브젝트 풀을 이용해서 생성, 제거를 반복하지 않고 계속해서 가져다 쓰는 기능을 구현했다. 하지만 맨 처음 풀 사이즈만큼 적들이 생성되고 죽고 나면 다시 리스폰되지 않는 현상이 발생했다.

 

private IEnumerator DestroyAfterDelay(float delay)
    {
        yield return new WaitForSeconds(delay);

        Destroy(gameObject);	// 오브젝트 파괴
    }

그 이유는 적이 죽고 오브젝트를 씬에서 삭제하는 코루틴에서 적 오브젝트 자체를 파괴해버려서 다시 큐에 들어가지 못했기 때문에 생성되지 않았다.

 

private IEnumerator DestroyAfterDelay(float delay)
    {
        yield return new WaitForSeconds(delay);

        ObjectPoolManager.Instance.ReturnToPool(gameObject, "Enemy");	// 오브젝트 풀로 다시 넣음
    }

그래서 오브젝트를 파괴하는 코드를 제거하고 오브젝트 풀로 다시 넣는 코드를 추가했다.

 

리스폰된 적들이 안 죽음

 하지만 초기 생성 적들은 정상적으로 적에게 맞고 쓰러지며 머리카락이 없었는데, 리스폰 된 오브젝트들은 이미 죽은 상태였던 오브젝트가 생성됐다. 그래서 플레이어가 오브젝트는 추적하지만 아무리 공격해도 적들이 죽지 않았다.

그 이유는 다시 생성된 오브젝트들이 초기 값으로 설정되지 않은 채 생성되었기 때문이다.

 

private IEnumerator DestroyAfterDelay(float delay)
{
    yield return new WaitForSeconds(delay);

    // 오브젝트 풀로 다시 넣음
    ObjectPoolManager.Instance.ReturnToPool(gameObject, "Enemy");

    // 죽은 적들 초기화
    enabled = true;
    Controller.enabled = true;
    hairActivate.SetActive(false);
    Animator.ResetTrigger("Die");
    Health.health = maxHealth;
    Health.IsDie = false;
}

그래서 풀에 넣은 뒤 오브젝트 설정을 초기 값으로 바꿔주는 코드들을 추가한다. 그러면 오브젝트가 풀에서 나올 때 초기 설정 값으로 나오게 된다.

 

참조 변수 값이 제대로 할당되지 않음

public void TakeDamage(int damage)
{
    if (health == 0) return;

    health = Mathf.Max(health - damage, 0);

    if(IsEnemy) // 에너미일 때
    {
        OnTakeDamage?.Invoke(); // 데미지 받을 때 깜빡깜빡
        ShowHitText();
    }

    if (health == 0)
    {
        IsDie = true;
        OnDie?.Invoke();
    }
}

하지만 여전히 죽지는 않는 모습을 보였는데, 그 이유는 체력이 정상적으로 회복되지 않아서 애초에 체력이 0이었기 때문이다. 그래서 Die 이벤트가 호출되지 않고 그냥 return 돼서 추적만 되고 죽지 않았다.

 

public HealthSystem Health { get; private set; }

해결을 위해서는 체력을 100으로 초기화 해줘야 하는데, 현재 클래스에서 체력 데이터를 받아오는 변수를 프로퍼티를 이용해서 가져오고 있기 때문에 그냥 Health.health에 값을 할당하면 적용되지 않는다.

 

public void ResetHealth()    // 적 재생성 시 체력 초기화
{
    health = maxHealth;
}

그래서 실제 값을 바꿀 수 있도록 HealthSystem 클래스에서 체력을 다시 채워주는 메서드를 만들어서 호출한다.

 

private IEnumerator DestroyAfterDelay(float delay)
{
    yield return new WaitForSeconds(delay);

    // 오브젝트 풀로 다시 넣음
    ObjectPoolManager.Instance.ReturnToPool(gameObject, "Enemy");

    // 죽은 적들 초기화
    enabled = true;
    Controller.enabled = true;
    hairActivate.SetActive(false);
    Animator.ResetTrigger("Die");
    Health.ResetHealth();
    Health.IsDie = false;
}

위 문제점을 해결한 최종 코드와 실행 화면이다. 사용이 끝난 오브젝트를 파괴하지 않고 재사용하기 위해서 오브젝트 풀에 넣고, 그와 동시에 초기 값을 할당해서 맨 처음 생성된 오브젝트와 같은 상태로 만들어준다. 이 과정에서 프로퍼티로 가져온 변수를 사용할 때에는 값이 정상적으로 변하지 않을 수 있기 때문에, 필요한 변수가 있는 클래스에서 계산식을 메서드로 구현해 값을 리턴해오는 방향으로 해결할 수 있다.

 

[ 회고 ]

팀 작업을 하면서 적 이동 및 구현 기능을 담당하신 분이 작성하신 코드에 내가 만든 오브젝트 풀을 합치는 과정에서 다소 불필요한 로직이나 코드가 발생했었다. 왜냐하면 팀원분은 적 오브젝트가 이동하고 공격하고 죽는 기능 자체만 구현하면 됐기 때문이고, 나는 이 오브젝트들을 효율적으로 관리하기 위해 재생성까지 고려해야 했기 때문이다. 이 과정에서 팀원 분들의 코드를 파악하고 있는 것도 매우 중요하다고 느꼈고, 오브젝트의 상태가 바뀐다면 처음 상태를 원할 때 초기 값을 할당해 주는 것을 잊지 말아야 한다는 것을 깨달았다.

 

 

728x90
반응형