내일배움캠프 TIL

내일배움캠프 59일차 TIL "작물이 두번 설치되던 현상"

Jooglorystar 2024. 12. 10. 21:00

 

 

개발을 진행하면서, 데이터를 저장하고, 다시 불러오는 작업 또한 같이 진행되었다. 

 

해당 작업을 하던 도중 다음과 같은 문제를 발견했다.

 

 

 

작물이 있는 Farm Scene에서 다른 Scene으로 넘어갔을 때, 사라져야 했을 작물 오브젝트가 사라지지 않고 존재했다.

 

Farm Scene는 CropLoader라는 스크립트가, 씬이 비활성화 될 때 오브젝트 풀에서 생성한 작물 오브젝트를 다시 오브젝트 풀로 반환하는 메서드가 있었기에, 원래대로라면 사라지는것이 맞았다.

 

// CropLoader의 OnDisable() 메서드
private void OnDisable()
{
    GameManager.Instance.CropM.ReleaseCrops();
}

// CropManager의 실제 작동하는 메서드들
public void ReleaseCrops()
{
    foreach (var (cropPosition, cropState) in cropStateDictionary)
    {
        ReleaseCropObject(cropState);
    }
}

private void ReleaseCropObject(CropState p_cropState)
{
    GameManager.Instance.PoolM.ReleaseObject(PoolTag.CropGrowthPrefab, p_cropState.spriteResolver.gameObject);
}

 

 

 

그리고 다시 Farm Scene으로 돌아갔을 때, 중복으로 생성되는 것도 확인했다.

 

 

실제로, Farm Scene에 돌아왔을 때, 다시 작물을 생성하기 위해 기능이 있는 것도 맞았다.

 

그래서 나는 처음에는 작물을 처음 생성할 때, 제대로 오브젝트가 확인이 되지 않는 것이 원인이라고 생각하여,

ReleaseObject()메서드에 중단점을 찍고 확인해봤다.

 

그러나 모든 메서드들은 정상적으로 작동을 하고 있는 상태였다.

저장된 데이터가 로드되면서 작물의 정보도 제대로 불러 와지고, 생성도 제대로 되며, 다시 비활성화 되는 것도 일단은 오류없이 정상적으로 작동되고 있었다.

 

 

실제 원인은 다소 간단했는데, 결론부터 말하면 처음 로드 될 때, 작물이 중복으로 생성되고 있었다.

 

public void LoadFromGameState()
{
    GameManager.Instance.DataBaseM.seedDatabase.Init();
    foreach (CropSaveData cropSaveData in gameState.cropSaveDatas)
    {
        CropState cropState = new CropState();

        cropState.seedSO = GameManager.Instance.DataBaseM.seedDatabase.GetByID(cropSaveData.seedItemCode);
        cropState.growthStage = cropSaveData.growthStage;
        cropState.growingDate = cropSaveData.growingDate;

        GetCropObject(cropSaveData.cropPosition, cropState);
    }
}

public void LoadCropFromCropStateDictionary()
{
    foreach (var (cropPosition, cropState) in cropStateDictionary)
    {
        GetCropObject(cropPosition, cropState);
    }
}

 

작물 오브젝트가 생성되는 것은 GetCropObject()메서드에서만 실행된다.

LoadFromGameState()는 게임이 실행될 때, 한번 실행되고, LoadCropFromCropStateDictionary()는 CropLoader에서 실행되며, FarmScene이 활성화 될 때, 실행된다.

 

즉, 게임이 실행될 때, LoadFromGameState()를 통해 한번 생성되고, FarmScene이 활성화되면서 LoadCropFromCropStateDictionary()에서 한 번 더 작물 오브젝트가 생성된 것이었다.

 

실제로 두번째에 생성된 작물들은 Farm Scene이 비활성화 될 때, 정상적으로 같이 비활성화 되었지만, 처음 활성화된 작물들은 비활성화 되지 않았다. 이 비활성화되지 않은 첫번째 작물들이 처음 발견한 오류였다.

 

 

해결은 다음과 같이 했다.

 

public class CropState
{
    public int growthStage;
    public int growingDate;
    public SeedSO seedSO;
    public SpriteResolver spriteResolver;
    public bool isPlanted;
}

 

우선 '심어짐'을 알 수 있는 bool 값을 CropState 클래스에 추가하고,

 

private void GetCropObject(Vector3Int p_cropPosition, CropState p_cropState)
{
    if (p_cropState.isPlanted) return;

    GameObject cropObject = GameManager.Instance.PoolM.GetObject(PoolTag.CropGrowthPrefab);
    p_cropState.isPlanted = true;
    cropObject.name = $"{p_cropPosition.x}_{p_cropPosition.y}";
    cropObject.transform.position = GameManager.Instance.TilemapM.GroundTilemap.GetCellCenterWorld(p_cropPosition);

    SpriteResolver spriteResolver = cropObject.GetComponent<SpriteResolver>();

    p_cropState.spriteResolver = spriteResolver;

    if (!cropStateDictionary.ContainsKey(p_cropPosition))
        cropStateDictionary.Add(p_cropPosition, p_cropState);

    GameManager.Instance.TilemapM.tileDataMap[p_cropPosition].Seed = p_cropState.seedSO;

    UpdateCropSprite(p_cropPosition);
}

private void ReleaseCropObject(CropState p_cropState)
{
    GameManager.Instance.PoolM.ReleaseObject(PoolTag.CropGrowthPrefab, p_cropState.spriteResolver.gameObject);
    p_cropState.isPlanted = false;
}

 

오브젝트 풀에서 가져올 때 해당 bool 값을 true로 하고, 반환할 때 false로 했다.

그리고 심으려는 작물이 이미 심어져 있을 경우 return을 하여 메서드가 작동하지 않도록 했다.

 

위 작업을 하니, 작물을 두번 심는 현상을 멈출 수 있었다.