
기존 오류 코드
private void CheckBushStatus()
{
Vector3 center = transform.TransformPoint(_bushCollider.center);
Vector3 halfExtents = _bushCollider.size / 2f;
Quaternion rotation = transform.rotation;
Collider[] hitColliders = Physics.OverlapBox(center, halfExtents, rotation);
List<int> currentInsidePlayersId = new List<int>();
foreach (Collider hitCollider in hitColliders)
{
PlayerController pc = hitCollider.gameObject.GetComponent<PlayerController>();
if (pc != null)
{
currentInsidePlayersId.Add(pc.Id);
}
}
foreach (int oldId in _insidePlayersId)
{
if (!currentInsidePlayersId.Contains(oldId))
{
GameObject exGo = Managers.Object.FindById(oldId);
if (exGo != null && exGo.TryGetComponent<PlayerController>(out PlayerController exPc))
BushExitRender(exPc);
}
}
}
콜라이더 내부에 있는 객체 목록을 통해서 Bush를 구현했다.
분명 OnTriggerExit, OnTriggerEnter를 사용해도 되지만, 점멸을 사용할 때 OnTriggerExit가 호출이 되지 않아서 투명화가
계속 지속되는 문제를 경험했다.
그렇기 때문에 FixedUpdate 문에서 계속해서 확인하고 있는데,
InvalidOperationException: Collection was modifie 오류가 발생했다.
foreach 루프를 순회하는 도중에 발생한 것인데, 추측 상으로 C++을 공부했을 때 순회하는 도중 List가 변경된다면 반복자는 변경되지 않기 때문에 문제가 발생한다고 공부했다.
C#에서는 반복자(Eumerator)라는 객체를 사용하는데, 이는 순회가 완료될 때까지 절대 변경되어서는 안 된다는 것을 전제로 한다고 한다.
때문에 도중에 수정/제거를 하게 되면 컬렉션의 상태가 불안정하고 판단하고 즉시 오류를 발생시켜 프로그램을 충돌을 막는다.
해결책
foreach문을 사용하는 것이 아닌 for 루프로 변경해야 한다. 특히 제거 작업이 수반될 때는 역방향 for루프가 가장 안전하다.
그 이유는 요소를 제거했을 때 발생하는 인덱스 변화가 아직 처리하지 않은 요소에 영향을 주지 않기 때문에 "인덱스 안전성" 을 확보할 수 있다.
private void CheckBushStatus()
{
Vector3 center = transform.TransformPoint(_bushCollider.center);
Vector3 halfExtents = _bushCollider.size / 2f;
Quaternion rotation = transform.rotation;
Collider[] hitColliders = Physics.OverlapBox(center, halfExtents, rotation);
List<int> currentInsidePlayersId = new List<int>();
foreach (Collider hitCollider in hitColliders)
{
if (hitCollider.TryGetComponent<PlayerController>(out PlayerController pc))
currentInsidePlayersId.Add(pc.Id);
}
List<int> currentInsidePlayersId = new List<int>();
for (int i = _insidePlayersId.Count - 1; i >= 0; i--)
{
int oldId = _insidePlayersId[i];
if (!currentInsidePlayersId.Contains(oldId))
{
GameObject exGo = Managers.Object.FindById(oldId);
if (exGo != null && exGo.TryGetComponent<PlayerController>(out PlayerController exPc))
{
BushExitRender(exPc);
}
}
}
}
안에 있는 객체를 확인한 후, 안전하게 역방향 반복문을 활용해 로직을 안전하게 처리한다.
'이론 > 엔진' 카테고리의 다른 글
| [Unity 포트폴리오] 이터널리턴 코발트 프로토콜 모작 완성! (0) | 2025.12.14 |
|---|---|
| [Unity] Line Shader 관련 (0) | 2025.11.23 |