오늘은 특별히 뭔가 많이 작업했다기 보다는 R&D와 코드 분석 위주로 진행했다.
새로 분배받은 업무인 일일 무료 뽑기와 광고 뽑기에 대한 개요와 R&D 과정에 대해 정리하려고 한다.
일일 무료 뽑기와 광고 뽑기는 다음과 같이 작동한다.
우선은 일일 무료 뽑기부터 구현하기 위해 다양한 자료를 찾아봤다. 그 중에서도 아래의 링크에서 사용한 방식을 사용하여 구현하는 편이 가장 적절하다고 판단했다.
https://hsh12345.tistory.com/190
여기에서는 보상 초기화 날짜를 string으로 저장한 후 현재 시간과 비교하여 일일 보상을 받을 수 있는지 확인하는 방식을 취하고 있다. InfoManager의 내용을 다루지 않고 있어 바로 판단하기에는 내용이 어렵긴 하지만, 핵심은 텍스트로서 날짜를 비교한다는 내용이었다.
해당 방식이 적합하다고 생각한 이유는 앞으로 이와 같은 무료 뽑기에 대한 일일 획득 여부나 초기화 시간 등을 데이터베이스에 저장해야 하기 때문이다. 파이어베이스에서는 아무래도 직접적으로 Time에 대한 변수를 저장하긴 어려우니 string으로 저장한 다음 불러와서 하는 방식이 적합하다고 생각했다.
따라서 아래와 같의 의사 코드를 작성하였다.
using System;
using UnityEngine;
using UnityEngine.UI;
public class RandomGachaSystem : MonoBehaviour
{
[Header("Reference")]
[SerializeField] private CharacterDatabase _data;
[SerializeField] private ItemProbabilitySO _prob;
[SerializeField] private GachaResultUI _resultUI;
[Header("UI")]
[SerializeField] private Button _dailyButton;
[SerializeField] private Button _oneGachaButton;
[SerializeField] private Button _tenGachaButton;
// 확률 소수점 자릿수
[Header("ProbOffset")]
[SerializeField] private int digits = 0;
private WeightedRandom<Grade> _gradeRandom = new WeightedRandom<Grade>();
private void Awake()
{
RandomInit(_prob);
_dailyButton.onClick.AddListener(() => ItemSelect(1));
_oneGachaButton.onClick.AddListener(() => ConsumeGoodsButtonClick(1));
_tenGachaButton.onClick.AddListener(() => ConsumeGoodsButtonClick(10));
}
private void RandomInit(ItemProbabilitySO probability)
{
for(int i = 0; i < probability.ItemsProbability.Count; i++)
{
Grade grade = probability.ItemsProbability[i].ItemGrade;
int value = (int)(probability.ItemsProbability[i].Probability * (int)Math.Pow(10, digits));
_gradeRandom.Add(grade, value);
}
}
// 확률 변동 없는 캐릭터 뽑기
private UnitData ReturnData()
{
Grade grade = _gradeRandom.GetRandomItem();
return _data.GetRandomUnitByGrade(grade);
}
// 확률 변동 있는 캐릭터 뽑기
private UnitData ReturnDataBySub()
{
Grade grade = _gradeRandom.GetRandomItemBySub();
return _data.GetRandomUnitByGrade(grade);
}
private void FreeOrAdButtonClick()
{
// 일일 뽑기가 가능한지 확인
// 가능하면 ItemSelect(1) 진행
// 불가능할 시 광고 뽑기 진행 여부 확인
// 광고 뽑기가 가능한지 확인
// 가능하면 ItemSelect(1) 진행
// 불가능할 시 Return(경고팝업 띄우기)
}
private void ConsumeGoodsButtonClick(int number)
{
// 재화 상태 확인 절차 진행
ItemSelect(number);
}
// 확률 변동이 없는 가중치 확률
private void ItemSelect(int number)
{
if (_gradeRandom.GetList() == null) RandomInit(_prob);
for(int i = 0; i < number; i++)
{
UnitData data = ReturnData();
_resultUI.HeroGachaUpdate(data, i);
}
_resultUI.gameObject.SetActive(true);
}
// 천장이 있는 가중치 확률
private void ItemSelectBySub(int number)
{
if (_gradeRandom.GetList() == null) RandomInit(_prob);
for(int i = 0; i < number; i++)
{
ReturnDataBySub();
}
}
}
using System;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class RewardInfo
{
public string date; // 초기화 시간
public int state; // 획득 여부
}
public class TimeManager : MonoBehaviour
{
#region Singleton
public static TimeManager Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
}
#endregion
// 예시 : 일일퀘스트 초기화 및 획득 정보
[SerializeField] private List<RewardInfo> _dailyRewardInfo;
// 예시 : 주간퀘스트 초기화 및 획득 정보
[SerializeField] private List<RewardInfo> _weeklyRewardInfo;
[SerializeField] private RewardInfo _dailyGachaRewardInfo;
public void LoadDailyGachaResetTimeInfo()
{
// 데이터베이스에서 정보를 로드
}
public void SaveDailyGachaResetTimeInfo()
{
// 데이터베이스에 정보를 업로드
}
public bool HasObtainedGachaReward()
{
// 정보를 바탕으로 보상 획득 가능 여부 체크
return true;
}
}
이와 같이 의사 코드를 짰는데 문제가 있다. 그것은 데이터베이스 자체를 관리하고 있는 담당자가 있다 보니 데이터베이스를 건들여도 되는지 의문이 드는 것이었다. 이 부분에 대해서 결과적으로 전체 회의를 통해서 어떻게 관리할 것인가에 대한 이야기가 오갔다.
회의 결과에 대해 이야기하지만 결론은 아래와 같이 났다.
해당 작업이 진행될 시기는 기획팀의 데이터 테이블이 나올 것으로 예상되는 9월 1일이며, 이에 따라 나는 우선 일일 무료 뽑기 및 광고 보상은 바로 데이터베이스로 연결하는 것이 아닌, 로컬로 우선 테스트를 진행한 후 나중에 데이터베이스 연결을 진행하는 것으로 얘기되었다.