
건축 시스템을 개발하면서, 씬간 이동시 건설된 오브젝트를 비활성화하고, 다시 배치하는 것을 구현 하던중 오류가 발생했다.
// 건물 배치시 Dictionary에 추가되는 부분
_buildingDataDictionary.Add(_objectToBuild.area.position, _objectToBuild);
// 건물 회수
private void ReleaseBuilding(GameObject p_building)
{
GameManager.Instance.PoolM.ReleaseObject(PoolTag.Building, p_building);
}
// 복수 건물 회수
public void ReleaseBuildings()
{
foreach(var (buildingPosition, buildingData) in _buildingDataDictionary)
{
ReleaseBuilding(buildingData.gameObject);
}
}
// 건물 재배치 메서드
public void LoadBuildings()
{
foreach (var (buildingPosition, buildingData) in _buildingDataDictionary)
{
Building building = GameManager.Instance.PoolM.GetObject(PoolTag.Building).GetComponent<Building>();
_buildingDataDictionary[buildingPosition] = building;
building.SetBuilingData(buildingData.buildingData);
building.transform.position = buildingPosition;
}
}
기본적으로 건물을 배치할 때, _buildingDataDictionary에 좌표와 Building 을 저장하고,
이전에 사용한 CropLoader에서 씬 비활성화시 Release하고 활성화시 다시 Get 하는 것을 생각했었다.
당연히 이 메서드에서 예외 오류가 발생했다.
원인은 LoadBuildings()였다.
// 건물 재배치 메서드
public void LoadBuildings()
{
foreach (var (buildingPosition, buildingData) in _buildingDataDictionary)
{
Building building = GameManager.Instance.PoolM.GetObject(PoolTag.Building).GetComponent<Building>();
_buildingDataDictionary[buildingPosition] = building;
building.SetBuilingData(buildingData.buildingData);
building.transform.position = buildingPosition;
}
}
우선 오류 코드는 다음과 같았다.
InvalidOperationException: Collection was modified; enumeration operation may not execute.
System.Collections.Generic.Dictionary2+Enumerator[TKey,TValue].MoveNext () (at <17d9ce77f27a4bd2afb5ba32c9bea976>:0)
foreach문을 사용하던 도중 중간에 _buildingDataDictionary값을 변경한 것이 오류의 원인이었다.
foreach문은 반복하기 전에 그 콜렉션의 내부 내용을 저장하고, 반복문을 실행한다.
그리고 내부 정보가 변경되면 예외가 발생하게 되어있다.
왜냐하면 순회중 값이 추가되거나, 수정이 된다면, 순회가 불안정 해질 수 있었기에 순회중 값 수정을 막은 것이다.
처음 코드에서 굳이 foreach에서 값을 수정하려고 했던 이유는, ReleaseBuildings 부분이 제대로 작동하지 않았기 때문이다. 처음에는 비활성이 제대로 되지만, 다시 로드될 경우, 그 오브젝트는 _buildingDataDictionary에 저장된 Building과는 다른 Building이고 오브젝트 였기에 두번째부턴 제대로 비활성화가 되지 않았다.
그래서 해당 딕셔너리를 수정하려고 했던 것이다.
그래서 아예 정보와 건물을 따로 저장하는 것이 나을 것 같았기에 다음과 같이 수정하였다.
// 설치된 건물의 정보와 설치된 건물 오브젝트를 분리
private Dictionary<Vector3Int, BuildingSO> _buildingDataDictionary = new Dictionary<Vector3Int, BuildingSO>();
private List<Building> _buildings = new List<Building>();
// 설치 될 때 각각 추가해주는 부분
_buildingDataDictionary.Add(_objectToBuild.area.position, _objectToBuild.buildingData);
_buildings.Add(_objectToBuild);
private void ReleaseBuilding(GameObject p_building)
{
GameManager.Instance.PoolM.ReleaseObject(PoolTag.Building, p_building);
}
// 건물 리스트를 통해 비활성화 및 리스트 초기화
public void ReleaseBuildings()
{
foreach(Building building in _buildings)
{
ReleaseBuilding(building.gameObject);
}
_buildings.Clear();
}
// Load시 건물 오브젝트를 리스트에 다시 추가
public void LoadBuildings()
{
foreach (var (buildingPosition, buildingData) in _buildingDataDictionary)
{
Building building = GameManager.Instance.PoolM.GetObject(PoolTag.Building).GetComponent<Building>();
_buildings.Add(building);
building.SetBuilingData(buildingData);
building.transform.position = buildingPosition;
}
}
위 코드대로 수정하니 문제 없이 동작할 수 있었다.
'내일배움캠프 TIL' 카테고리의 다른 글
| 내일배움캠프 66일차 TIL "상점 기능 구상" (0) | 2024.12.19 |
|---|---|
| 내일배움캠프 65일차 TIL "InstanceID" (0) | 2024.12.18 |
| 내일배움캠프 63일차 TIL "프로젝트 중간 점검" (0) | 2024.12.16 |
| 내일배움캠프 62일차 TIL "2D 타일맵 기반의 건축기능" (0) | 2024.12.13 |
| 내일배움캠프 61일차 TIL "커스텀 에디터 기능" (0) | 2024.12.12 |