
저녁 시간에 이야기를 하다가 다른 팀은 회고록을 작성하고 있다는 사실을 알게 되었다. 그 외에도 개발 문서, 버그 리포트 등 다양한 문서 작업을 하고 있는 팀을 보며 우리도 해야할 것 같은 생각이 들었지만, 막상 TIL 말고도 다른 문서 작업을 하려니 엄두가 나질 않는다.
그래서 회고록은 TIl로 대체하기로 하고 대신 TIL을 쓸 때 버그 리포트와 비슷한 형식을 추가로 작성해보려고 한다. 사실 프로젝트 기간에 버그가 없는 날은 존재하지않기 때문에 매일 작성해야하지않을까.
남은 Build Issue이번에 공유하려는 코드는 랜덤 드랍 테이블 생성 기능으로, 몬스터에 드랍테이블을 설정할 때 고정된 아이템만 나오는 것이 아니라, 후보 아이템 중에 랜덤으로 드랍되는 기능이다.
RandomLootTable class랜덤 드랍 테이블을 설정하기 위한 필드와 메서드를 가지는 클래스로, CSV 파일을 바탕으로 만든 아이템과 루트 테이블 데이터를 참조하며, 루트 테이블의 id를 입력하여 개별적인 랜덤 드랍 테이블을 설정하는 것이 가능하다.
public class RandomLootTable : MonoBehaviour
{
// 생성에 사용될 Dictionary 데이터
[SerializeField] private LootDictionary _lootDic;
[SerializeField] private ItemDictionary _itemDic;
// 인스펙터 상에서 입력할 테이블 ID
[SerializeField] private string _id;
// 루트 테이블 데이터를 세분화하여 저장
private List<int> _itemId;
private List<int> _itemStack;
private List<int> _itemWeight;
private int _itemCount;
public List<ItemBase> _resultItems;
public List<int> _resultItemAmount;
private void Start()
{
Init();
int gridNum = SetGridAmount();
SetItem(gridNum);
}
private void Init(){}
private int SetGridAmount(){}
private void SetItem(){}
}
Init Method루트 테이블을 세분화하는 작업과 루트 테이블에 포함된 아이템의 수를 저장한다.
private void Init()
{
_itemId = new List<int>();
_itemStack = new List<int>();
_itemWeight = new List<int>();
for (int i = 0; i < _lootDic.LootTable[_id].Count; i+=3)
{
// 테이블에 포함된 아이템 별 ID
_itemId.Add(_lootDic.LootTable[_id][i]);
// 테이블에 포함된 아이템 별 드랍 수량
_itemStack.Add(_lootDic.LootTable[_id][i+1]);
// 테이블에 포함된 아이템 별 가중치
_itemWeight.Add(_lootDic.LootTable[_id][i+2]);
}
// 테이블에 포함된 아이템 수
_itemCount = _itemId.Count;
}
SetGridAmount Method드랍될 아이템의 수를 결정하는 메서드로 가중치에 따라 0~6 사이의 숫자를 반환한다.
private int SetGridAmount()
{
// 아이템 수에 대한 가중치를 저장한 데이터
int volume = _lootDic.LootGridTable[_id].Count;
// 난수와 비교하기 위한 가중치 합을 저장할 배열
int[] weightSums = new int[volume];
for (int i = 0; i < volume; i++)
{
for (int j = 0; j < i + 1; j++)
{
weightSums[i] += _lootDic.LootGridTable[_id][j];
}
}
// 모든 가중치를 더한 값을 최대로 한 난수 생성
int rndNum = Random.Range(0, weightSums[volume - 1]);
// 루트 테이블에 포함된 아이템 숫자와 비교하여 드랍될 아이템 수 결정
for (int i = 0; i < volume; i++)
{
if (rndNum < weightSums[i]) return i < _itemCount ? i : _itemCount;
}
return -1;
}
SetItem Method드랍될 아이템의 수가 결정되면, 어떤 아이템을 드랍할 것인지 정해주는 메서드
private void SetItem(int volume)
{
// 드랍할 아이템을 저장하는 List
_resultItems = new List<ItemBase>();
// 드랍할 아이템의 수량을 저장하는 List
_resultItemAmount = new List<int>();
// 추가할 아이템의 수
int remaining = _itemCount;
// 추가할 아이템이 남아있으면
while (remaining > 0)
{
// 남은 아이템이 없으면 반복문 종료
if (_itemId.Count == 0) break;
// 가중치 합 저장
int[] weightSums = new int[remaining];
for (int i = 0; i < remaining; i++)
{
for (int j = 0; j < i + 1; j++)
{
weightSums[i] += _itemWeight[j];
}
}
// 0과 모든 가중치를 더한 값 사이의 난수 생성
int rndNum = Random.Range(0, weightSums[remaining - 1]);
for (int i = 0; i < remaining; i++)
{
// 가중치에 따라 아이템이 정해지면
if (rndNum < weightSums[i])
{
// 드랍할 아이템 저장
_resultItems.Add(_itemDic.ItemDic[_itemId[i]]);
// 드랍할 아이템 수량 저장
_resultItemAmount.Add(_itemStack[i]);
// 해당 아이템 제거
_itemId.Remove(_itemId[i]);
_itemStack.Remove(_itemStack[i]);
_itemWeight.Remove(_itemWeight[i]);
// 남은 수량 -1
remaining--;
break;
}
}
}
}