XR플밍 - 12. UnityEngine3D Reactive 프로그래밍 - 기업협약 프로젝트 21일차 (9/15)

이형원·2025년 9월 15일
0

XR플밍

목록 보기
197/215

1. 금일 한 업무 정리

  • 본인이 만든 TempDataManager를 다른 팀원이 작업한 DataManager로 기능을 옮기고, 통합하는 작업 진행
  • 캐릭터 편성에서, 편성한 캐릭터를 표시하는 UI 기능 추가
  • 그 외 UI 폴리싱 및 버그 수정

2. 문제의 발생과 해결 과정

2.1 데이터 통합 작업

TempDataManager의 데이터를 DataManager로 옮기는 작업 자체는 그리 어려운 것이 아니다. 다만, 좀 더 체계적으로 정리하기 위해서, 가급적 옮기는 데이터를 클래스로 따로 분류하여 저장하는 방식을 사용했다.

using Cysharp.Threading.Tasks;
using System.Collections.Generic;
using UnityEngine.AddressableAssets;

public class DataManager : Singleton<DataManager>
{
    // 유닛 데이터 관련
    public Dictionary<string, UnitData> UnitDataDic;
    public UnitData[] EnemyUnitDatas;
    public SynergyDatabase SynergyDB;

    // 프리셋 데이터 관련
    public PresetDatabase PresetDB { get; private set; } = new PresetDatabase();

    // 맵 데이터 관련
    public MapDatabase MapDB { get; private set; } = new MapDatabase();

    private void Awake()
    {
        InitData().Forget();
        PresetDB.InitPresetData();
        MapDB.InitMapData();
    }

    #region UniData

    public async UniTask InitData()
    {
        await PreLoadData();
        await CsvDownload();
    }

    private async UniTask CsvDownload()
    {
        CsvLoadData data = await Addressables.LoadAssetAsync<CsvLoadData>("Data/CsvLoadData");
        CsvDownloader csvDownloader = new CsvDownloader(data);

        csvDownloader.DownloadDataAsync().Forget();
    }

    private async UniTask PreLoadData()
    {
        UniTask[] tasks = new UniTask[2];

        tasks[0] = PreLoadSynergyDB();
        tasks[1] = PreLoadUnitDatas();

        await UniTask.WhenAll(tasks);
    }

    private async UniTask PreLoadUnitDatas()
    {
        EnemyUnitDatas = await Manager.Resources.LoadAll<UnitData>("EnemyUnitData");
        UnitData[] UnitDatas = await Manager.Resources.LoadAll<UnitData>("UnitData");

        UnitDataDic = new Dictionary<string, UnitData>(UnitDatas.Length);

        foreach (var unitData in UnitDatas)
        {
            if (!UnitDataDic.ContainsKey(unitData.Name))
                UnitDataDic.Add(unitData.Name, unitData);

            unitData.Init();
        }
    }    

    private async UniTask PreLoadSynergyDB()
    {
        SynergyDB = await Addressables.LoadAssetAsync<SynergyDatabase>("Database/SynergyDatabase");
        SynergyDB.Init();
    }

    public UnitData GetUnitData(string unitName)
    {
        return UnitDataDic.TryGetValue(unitName, out var unitData) ? unitData : null;
    }

    #endregion
}
using System.Collections.Generic;

public class PresetDatabase
{
    // 프리셋 관련
    private int _selectedPresetIndex = 0;
    public int SelectedPresetIndex => _selectedPresetIndex;
    private List<TeamPresetData> _presetData = new List<TeamPresetData>();
    public List<TeamPresetData> PresetData => _presetData;

    #region PresetData

    /// <summary>
    /// 프리셋 데이터 초기화
    /// 신규 유저여서 프리셋 데이터가 없는 경우와
    /// 이미 있는 데이터를 로드해야 하는 경우를 나눠야 함
    /// </summary>
    public void InitPresetData()
    {
        // 신규 유저일 경우(프리셋 데이터가 없을 경우)
        if (_presetData.Count == 0)
        {
            for (int i = 0; i < 2; i++)
            {
                _presetData.Add(new TeamPresetData(5));
            }
        }
        // TODO : 신규 유저가 아닐 경우(프리셋 데이터가 있을 경우)
        // TODO : DB에서 [프리셋] 데이터를 로드 후 캐싱
    }

    /// <summary>
    /// 프리셋을 확장함.
    /// </summary>
    /// <param name="size"></param>
    public void CreatePreset(int size)
    {
        _presetData.Add(new TeamPresetData(size));
        // TODO : DB에 [프리셋] 데이터를 저장
    }

    /// <summary>
    /// 현재 선택된 프리셋을 반환함.
    /// </summary>
    /// <returns></returns>
    public TeamPresetData ReadCurrentSelectedPreset()
    {
        if (_selectedPresetIndex == -1) return null;

        return _presetData[_selectedPresetIndex];
    }

    /// <summary>
    /// 현재 선택된 프리셋의 인덱스를 설정함.
    /// </summary>
    /// <param name="index"></param>
    public void SelectPresetIndex(int index)
    {
        _selectedPresetIndex = index;
    }

    #endregion
}
using System.Collections.Generic;
using UnityEngine;

public class MapDatabase : MonoBehaviour
{
    private MapDatabaseSO _mapDatabase;

    public void InitMapData()
    {
        // TODO : 임시로 Resouces.Load로 데이터를 로드 - 이후 DB로 로드하는 방식으로 변경
        _mapDatabase = Resources.Load<MapDatabaseSO>("MapDataSO");
    }

    public List<MapData> ReturnAllMapData()
    {
        return _mapDatabase.Maps;
    }

    public MapData ReturnMapData(int index)
    {
        return _mapDatabase.Maps[index];
    }
}

2.2 편성된 캐릭터를 UI로서 표기하기

기획에서 제공하거나 따로 요청한 기획이 없었지만, 디테일을 위해 추가해야 할 요소가 무엇이 있는지 고민하던 와중에 이와 같은 기능이 필요하다는 것을 느꼈다.

위의 캐릭터 편성 칸에서는 캐릭터 이름 등의 정보가 뜨지 않고 애니메이션 연출 위주로 살리다 보니, 어떤 캐릭터를 선택했는지 판별하기가 어렵다. 따라서 캐릭터 선택을 표시하는 UI가 필요하다.

이에 따라 해당 UI를 추가하려고 스크립트를 추가했다.

private void SelectedUpdate() 
{ // 캐릭터 편성 칸이 5칸에서 다른 크기로 변경될 가능성이 적다는 전제로 직접 5를 집어넣음, 유동성을
  // 주고 싶다면 _currentUnit의 길이를 직접 가져올 것
	for(int i = 0; i < 5; i++)
    {
    	UnitStatus data = _manager.GetCurrentPresetData(i);
        if (data != null && data == _status)
        {
        	_selectedImage.gameObject.SetActive(true);
            Debug.Log("실행됨"); break; 
        }
        if(i == 4) _selectedImage.gameObject.SetActive(false);
    } 
}

하지만 이와 같이 작성했을 때 논리적으로 오류가 없는 것으로 보이지만, 항상 거짓이 되어 편성됨 이미지가 뜨는 일이 없을 것이다,
해당 조건이 항상 거짓이 되는 이유는 다음과 같다.

public UnitStatus GetCurrentPresetData(int index)
{ 
	if (_currentPreset != null)
    {
    	return _currentPreset[index];
    } 
    return null;
}

해당 스크립트가 데이터를 읽어오는 방식의 코드는 다음과 같다.

다만 이를 통해 status 데이터를 가지고 왔을 경우 기존 프리셋에 있던 Status를 복사한다.(원래 저장된 Status와 복사된 Status는 참조상 저장되는 위치가 달라 다른 데이터로 간주.) 이 복사된 Status는 또다시 CharacterUnit에 저장된 _status와는 다른 위치에 저장된다. 따라서, 셋 다 다른 데이터이기 때문에 위의 함수는 항상 거짓이 된다.

따라서, 직접적으로 데이터를 비교하는 방식보다는, 고유번호를 이용한 방식으로 변경하는 것이 메모리 부담도 적고 확실한 방법이다.

public UnitStatus GetCurrentPresetData(int index)
{ 
	if (data != null && data.Data != null && data.Data.ID == _status.Data.ID)
	{
    	_selectedImage.gameObject.SetActive(true);
    	Debug.Log("실행됨");
    	break;
	}
    if(i == 4) _selectedImage.gameObject.SetActive(false);
}

3. 개선점 및 과제

3.1 업무분배

3.2 데이터 연결 작업

3.3 UI 폴리싱

3.4 리팩토링

profile
게임 만들러 코딩 공부중

0개의 댓글