0.들어가기에 앞서
작업물 합치기 단계를 계속 진행하고 있다. 슬슬 UI 연결과 게임매니저 데이터 연동 등의 작업을 하고 있다.
수리 UI 버튼 누를 시 수리항목, 내용, 필요 에너지 출력하는 부분, 수리하는 부분까지는 구현완료
게임매니저에 게임 데이터 영역에서 energy를 저장하기로 했다. 이에 따라 에너지의 증감에 대한 부분을 데이터로 저장하고, UI로 반영하는 작업을 완료했다.
아이템 확률 계산에 대한 의사코드만 우선 작성
오늘은 특별한 문제가 발생했다기 보다는 코드를 연결하는 과정에서 서로간 코드를 확인하고, 해석하는 과정이 있었다. 그 중에서 팀장님이 구현한 UI매니저에 대한 걸 다뤄보고자 한다.
내가 직접 작성한 코드는 아니다 보니, 전체적인 작동 방식의 흐름만 다뤄보려고 한다.
이와 같은 방식으로 겹겹이 뜨는 UI도 구현 가능하고, 단순한 한 겹의 UI도 구현 가능하다.
여기서 나의 경우에 크래프팅 UI에서 특정 버튼을 누르면 베이스캠프 수리라는 UI로 한 단계 더 들어가는 UI를 구현하는 경우, 아래와 같이 키워드를 설정하고 버튼의 OnClick 이벤트로 등록한다.
public void GoToRepairMenu()
{
GameManager.Instance.InGameUIManager.ShowUI(UIType.Repair);
}
public void GoBackToCraftUI()
{
GameManager.Instance.InGameUIManager.HideUI();
}
늘 UI매니저에 대해서 어떻게 생성해야 할지 고민이 많았는데, 이와 같은 방식으로 구현하는 것에 참신함을 느꼈다.
아이템 확률 계산 및 등장에 관해 어떻게 해야 할지 고민이 많았다. 하지만 의외로 번뜩이는 생각으로 현재 의사코드로 내용을 임시로 구현했다.
using System.Collections.Generic;
using UnityEngine;
enum BoxTier { Tier1, Tier2, Tier3 }
public class BoxItemRandomSystem : MonoBehaviour
{
[SerializeField] BoxTier _tier;
[SerializeField] BoxSystem _data;
[Header("Item - Normal")]
[SerializeField] ItemSO[] _itemA_Items1;
[Header("Item - Rare")]
[SerializeField] ItemSO[] _itemA_Items2;
[Header("Item - Unique")]
[SerializeField] ItemSO[] _itemA_Items3;
[Header("Item - Legendary")]
[SerializeField] ItemSO[] _itemA_Items4;
[Header("Journal - List")]
[SerializeField] CollectionSO[] _itemB_Journal;
[Header("Food")]
[SerializeField] ItemSO[] _itemC_Food;
[Header("Collectible - List")]
[SerializeField] CollectionSO[] _itemD_Collection;
private WeightedRandom<ItemSO> _weightedRandomA = new WeightedRandom<ItemSO>();
private WeightedRandom<CollectionSO> _weightedRandomD = new WeightedRandom<CollectionSO>();
private Stack<CollectionSO> _journalStack = new Stack<CollectionSO>();
private void Awake()
{
// Item A init
switch (_tier)
{
case BoxTier.Tier1: ItemAInit(300, 145, 50, 10);
break;
case BoxTier.Tier2: ItemAInit(150, 200, 100, 100);
break;
case BoxTier.Tier3: ItemAInit(50, 125, 200, 250);
break;
}
// Item B init
ItemBInit();
// Item C init
ItemCInit();
// Item D init
ItemDInit();
}
private void OnEnable()
{
ItemAddToBox();
}
private void OnDisable()
{
_data.RemoveAllItem();
}
private void ItemAddToBox()
{
ItemASelect();
ItemBSelect();
ItemCSelect();
ItemDSelect();
}
/// <summary>
/// Select Item A.
/// Item A is definitely collecitible, and the number of A item is 4.
/// </summary>
private void ItemASelect()
{
if (_weightedRandomA.GetList() == null) return;
for (int i = 0; i < 4; i++)
{
_data.AddItemToBoxSlot(_weightedRandomA.GetRandomItem());
}
}
/// <summary>
/// Set Item A weightRandom. (Materials)
/// </summary>
/// <param name="normal"></param>
/// <param name="rare"></param>
/// <param name="unique"></param>
/// <param name="legendary"></param>
private void ItemAInit(int normal, int rare, int unique, int legendary)
{
for(int i = 0; i < _itemA_Items1.Length; i++)
{
_weightedRandomA.Add(_itemA_Items1[i], normal);
}
for(int i = 0; i < _itemA_Items2.Length; i++)
{
_weightedRandomA.Add(_itemA_Items2[i], rare);
}
for(int i = 0; i < _itemA_Items3.Length; i++)
{
_weightedRandomA.Add(_itemA_Items3[i], unique);
}
for (int i = 0; i < _itemA_Items4.Length; i++)
{
_weightedRandomA.Add(_itemA_Items4[i], legendary);
}
}
private void ItemBSelect()
{
if(_journalStack.Count == 0) return;
// if(GameManager.Instance.DayNightManager.CurrentDay == key)
//{
// float randomNum = Random.Range(0.0f, value);
// if randonNum > value return;
// 콜렉션을 추가하는 함수(_journalStack.Pop());
//}
}
/// <summary>
/// Set Item B weightRandom. (Diary)
/// </summary>
private void ItemBInit()
{
for(int i = 0; i < _itemB_Journal.Length; i++)
{
_journalStack.Push(_itemB_Journal[i]);
}
// 현재 일지 아이템이 없고 확률 테이블을 만들 방법에 대해 고민하고 있어
// 의사 코드로 먼저 적습니다.
// 일차 = key, 확률 = value로 된 dictionary를 생성하고, 데이터 테이블의 정보를 SO로 만들어놓는다.
Dictionary<int, float> keyValuePairs = new Dictionary<int, float>();
// 딕셔너리 정보를 전부 저장
}
private void ItemCSelect()
{
// if(GameManager.Instance.DayNightManager.CurrentDay == key)
//{
// float randomNum = Random.Range(0.0f, value);
// if randonNum > value return;
// _data.AddItemToBoxSlot(_itemC_Food);
//}
}
/// <summary>
/// Set Item C weightRandom. (Food)
/// </summary>
private void ItemCInit()
{
// 현재 일지 아이템이 없고 확률 테이블을 만들 방법에 대해 고민하고 있어
// 의사 코드로 먼저 적습니다.
// 일차 = key, 확률 = value로 된 dictionary를 생성하고, 데이터 테이블의 정보를 SO로 만들어놓는다.
Dictionary<int, float> keyValuePairs = new Dictionary<int, float>();
// 딕셔너리 정보를 전부 저장
}
/// <summary>
/// Select Item D. (Collective)
/// </summary>
private void ItemDSelect()
{
if (_weightedRandomD.GetList() == null) return;
float randomNum = Random.Range(0.0f, 1.0f);
if (randomNum > 0.7f) return;
// need to make collection item slot in box inventory.
//_data.AddItemToBoxSlot(_weightedRandomD.GetRandomItem());
}
/// <summary>
/// Set Item D weightRandom. (Collective)
/// </summary>
private void ItemDInit()
{
for(int i = 0; i < _itemD_Collection.Length; i++)
{
_weightedRandomD.Add(_itemD_Collection[i], 1);
}
}
}
해당 부분에 대해 고민하는 방식은, GameManager의 GameData에 bool[] 값을 저장한 다음, 해당 조건에 따라 수리 버튼 활성화/비활성화 하는 방식을 생각해보고 있다.
아이템 확률이 일자별로 매일 확률이 달라지는 방식이며, 이를 상자 확률에 반영하기 위해서는 생각할 수 있는 방법이 해당 데이터를 Dictinary 형태로 생성하고 키(일자)를 바탕으로 값(확률)을 가져와서 확률 계산을 하는 방식을 생각해보고 있다.
3.2의 방식을 바탕으로 B와 C의 아이템 확률 뽑기를 구현한다.
수집품이라는 아이템 항목을 따로 저장할 슬롯이 필요하므로, 수집품을 구현하고 있는 다른 팀원에게 슬롯을 구현한 내용이 있는지 확인하고 수집품을 담을 슬롯을 구현해 B와 D를 구현한다.
수집품 아이템에는 일지와 수집품이 있는데, 둘 다 수집품으로 분류하고 유형을 나누는 편이 좋다고 생각한다. 이 부분에 대해 기획팀에 요청하려고 한다.
아이템 제작 중 이탈하면 아이템 제작이 불가능하거나, 제작중에 다른 아이템 버튼을 누르면 아이템이 결과물이 바뀌거나 제작 버튼 연발하면서 에너지를 낭비하는 방식에 대한 개선이 필요하다.