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];
}
}
기획에서 제공하거나 따로 요청한 기획이 없었지만, 디테일을 위해 추가해야 할 요소가 무엇이 있는지 고민하던 와중에 이와 같은 기능이 필요하다는 것을 느꼈다.
위의 캐릭터 편성 칸에서는 캐릭터 이름 등의 정보가 뜨지 않고 애니메이션 연출 위주로 살리다 보니, 어떤 캐릭터를 선택했는지 판별하기가 어렵다. 따라서 캐릭터 선택을 표시하는 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);
}