내일배움캠프/TIL

[내배캠][Unity6기][TIL] 풀 반환 오류 트러블슈팅

binary는 호남선 2025. 1. 9. 22:45

대환장파티의 풀 반환 오류를 드디어 해결했다!

오류의 원인이 되는 부분이 많았어서 하나하나 찾기 쉽지 않았는데 튜터님의 도움으로 해결할 수 있었다.

 

[ 문제 상황 ]

1. 풀에 이미 반환된 오브젝트가 2번 반환을 시도

2. 풀에서 가져온 타입과 다른 타입으로 풀에 반환

3. 풀에 반환할 오브젝트의 인덱스 에러

(추후 에러 로그 정보 추가 예정)

 

[ 문제 원인 ]

 1. 미니언 반환에서 이중 반환 및 타입이 맞지 않게 반환시키는 부분이 있었다.

public class Minion : Monster
{
    public override void ReturnToVillage()
    {
        base.ReturnToVillage();
        _summonerMonster.RemoveMinion(this);
        GameManager.Instance.RemoveActiveList(this);
        PoolManager.Instance.ReturnToPool<Minion>(data.poolTag, this);
    }
}
public abstract class Monster : MonoBehaviour
{
    public virtual void ReturnToVillage()
    {
        if (_coroutine != null) StopCoroutine(_coroutine);
        _coroutine = StartCoroutine(FadeOutAndReturnToPool());
    }

    private IEnumerator FadeOutAndReturnToPool()
    {
        GameManager.Instance.RemoveActiveList(this);
        PoolManager.Instance.ReturnToPool(data.poolTag, this);

        yield return null;
    }
}

부모 타입(Monster)로 먼저 ReturnToVillage 하며 Minion이 Monster 타입으로 반환되어 버린다.

public class summonerMonster : Monster
{
    private void ClearMinion()
    {
        if (MinionList == null || MinionList.Count == 0) return;

        foreach (Minion minion in MinionList)
        {
            GameManager.Instance.RemoveActiveList(minion);
            PoolManager.Instance.ReturnToPool(minion.data.poolTag, minion);
        }
        MinionList.Clear();
    }
}

foreach 실행 도중 몬스터 리스트에 변동이 있어 잘못된 인덱스를 참조하게 된다.

Summoner 몬스터의 ClearMinion이 실행되는 도중 Minion도 풀에 반환되는 상황이 되면 이중 반환이 되는 문제가 발생한다.

 

[ 문제 해결 ]

Monster의 ReturnToVillage에서 Minion이 아닌 경우에만 활성 리스트에서 삭제하고 풀에 반환하도록 수정

Minion은 본인의 스크립트에서 오버라이딩하여 삭제하고 풀 반환하게 만들기

public class Minion : Monster
{
    public void ReturnToVillage(bool remove)
    {
        base.ReturnToVillage();
        if (remove)
        {
            _summonerMonster.RemoveMinion(this);
        }
        GameManager.Instance.RemoveActiveList(this);
        PoolManager.Instance.ReturnToPool<Minion>(data.poolTag, this);
    }
}
public abstract class Monster : MonoBehaviour
{
    public virtual void ReturnToVillage()
    {
        if (_coroutine != null) StopCoroutine(_coroutine);
        _coroutine = StartCoroutine(FadeOutAndReturnToPool());
    }

    private IEnumerator FadeOutAndReturnToPool()
    {
        if (this.GetType().Name != "Minion")
        {
            GameManager.Instance.RemoveActiveList(this);
            PoolManager.Instance.ReturnToPool(data.poolTag, this);
        }

        yield return null;
    }
}

반복 중에 리스트 요소를 삭제하는 경우 foreach 대신 for 문을 사용해 뒤에서부터 삭제하도록 만들어 인덱스 에러 방지

해당 요소가 씬에 활성화되어있는지 확인 후 풀에 반환시키기

public class summonerMonster : Monster
{
    private void ClearMinion()
    {
        if (MinionList == null || MinionList.Count == 0) return;
        
        int mCount = MinionList.Count;
        for (int i = 0; i < mCount; i++)
        {
            if (MinionList[MinionList.Count - 1].gameObject.activeSelf)
            {
                MinionList[MinionList.Count - 1].ReturnToVillage(true);
            }
        }

        if (MinionList.Count > 0)
        {
            MinionList.Clear();
        }
    }
}