마법석의 확률은 다음과 같다.
마법석을 뽑았을 경우 조각에 대한 가중치 확률도 들어간다.
이를 구성하기 위해서 다음과 같이 SO를 구성했다.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "MagicStoneGachaSO", menuName ="Data/MagicStoneGachaSO")]
public class MagicStoneGachaSO : ScriptableObject
{
public List<RewardEntry> rewards;
}
[Serializable]
public class RewardEntry
{
public MagicStoneRewardType rewardType;
public float RewardProbability;
public List<PieceEntry> PieceEntries;
}
[Serializable]
public class PieceEntry
{
public int PieceNum;
public float PieceProbability;
}
public enum MagicStoneRewardType
{
MagicStone,
Gold500,
Gold1000,
Gold10000,
Dia50,
Dia100,
Dia1000
}
#region MagicStoneGachaButton
#region AdButton
/// <summary>
/// 광고 버튼 클릭 이벤트
/// </summary>
private async void StoneAdButtonClick()
{
// 일일 광고 가챠가 가능할 경우 실행
if (await DailyStoneAdGacha()) return;
// 광고 가챠가 불가능할 경우 경고 팝업
if (PopupManager.Instance != null)
{
PopupManager.instance.ShowPopup("일일 광고 가챠를 전부 사용하였습니다.");
}
}
/// <summary>
/// 광고 가챠의 가능 여부를 판별하고 가능할 시 광고 시청 후 가챠를 진행
/// </summary>
/// <returns></returns>
private async Task<bool> DailyStoneAdGacha()
{
// 광고 가챠가 가능할 때
if (TimeManager.Instance.CanObtainAdGachaReward(GachaType.Stone))
{
// 광고 가챠 쿨타임 업데이트
TimeManager.Instance.UpdateAdGachaResetTimeInfo(GachaType.Stone);
// 1회 뽑기 진행
await MagicStoneSelect(1);
TimeManager.Instance.OnDailyGachaInfoChanged?.Invoke();
return true;
}
return false;
}
#endregion
#region DailyButton
/// <summary>
/// 1회 뽑기 버튼 클릭 이벤트
/// </summary>
private async void StoneOneButtonClick()
{
// 일일 무료 뽑기가 가능할 때 해당 뽑기 우선 진행
if (await DailyStoneFreeGacha()) return;
ConsumeGoodsButtonClick(GachaType.Stone, 1);
}
/// <summary>
/// 일일 뽑기의 가능 여부를 판별하고, 가능할 시 횟수를 소모하고 진행
/// </summary>
/// <returns></returns>
private async Task<bool> DailyStoneFreeGacha()
{
// 일일 무료 뽑기가 가능할 때
if (TimeManager.Instance.CanObtainedFreeGachaReward(GachaType.Stone))
{
// 1회 뽑기 진행
await MagicStoneSelect(1);
// 일일 무료 뽑기 쿨타임 업데이트
TimeManager.Instance.UpdateDailyFreeGachaResetTimeInfo(GachaType.Stone);
return true;
}
return false;
}
#endregion
...
private async Task MagicStoneSelect(int number)
{
if (_magicStoneRewardRandom.GetList() == null) MagicStoneRandomInit(_stoneProb);
for (int i = 0; i < number; i++)
{
MagicStoneRewardType type = _magicStoneRewardRandom.GetRandomItem();
switch (type)
{
case MagicStoneRewardType.MagicStone:
MagicStoneSelection(i);
break;
case MagicStoneRewardType.Gold500:
await DBManager.Instance.AddGoldAsync(500);
_resultUI.StoneGachaUpdate(type, i, 500.ToString());
Debug.Log("골드 500");
break;
case MagicStoneRewardType.Gold1000:
await DBManager.Instance.AddGoldAsync(1000);
_resultUI.StoneGachaUpdate(type, i, 1000.ToString());
Debug.Log("골드 1000");
break;
case MagicStoneRewardType.Gold10000:
await DBManager.Instance.AddGoldAsync(10000);
_resultUI.StoneGachaUpdate(type, i, 10000.ToString());
Debug.Log("골드 10000");
break;
case MagicStoneRewardType.Dia50:
await DBManager.Instance.AddDiamondAsync(50);
_resultUI.StoneGachaUpdate(type, i, 50.ToString());
Debug.Log("다이아 50");
break;
case MagicStoneRewardType.Dia100:
await DBManager.Instance.AddDiamondAsync(100);
_resultUI.StoneGachaUpdate(type, i, 100.ToString());
Debug.Log("다이아 100");
break;
case MagicStoneRewardType.Dia1000:
await DBManager.Instance.AddDiamondAsync(1000);
_resultUI.StoneGachaUpdate(type, i, 1000.ToString());
Debug.Log("다이아 1000");
break;
}
}
_resultUI.gameObject.SetActive(true);
}
private void MagicStoneSelection(int index)
{
int pickedStone = UnityEngine.Random.Range(0, _stoneDatabase.MagicStoneDatas.Count);
MagicStoneData data = _stoneDatabase.MagicStoneDatas[pickedStone];
int pieces = _magicStonePieceRandom.GetRandomItem();
_resultUI.StoneGachaUpdate(data, index, pieces.ToString());
}
가챠 종류에 따라 편하게 선택할 수 있도록 TimeManager를 다음과 같이 변경하였다.
using System;
using UnityEngine;
public enum GachaType
{
Char,
Stone,
}
[Serializable]
public class RewardInfo
{
public long dateTicks; // DateTime을 Ticks로 저장
public int state; // 획득 여부 또는 스택 수
/// <summary>
/// 리워드 정보를 생성함.
/// </summary>
/// <param name="dateTicks">시간을 Long으로 변환</param>
/// <param name="state">획득여부 혹은 Stack수</param>
public RewardInfo(long dateTicks, int state)
{
this.dateTicks = dateTicks;
this.state = state;
}
/// <summary>
/// 시간 정보를 로드
/// </summary>
/// <returns></returns>
public DateTime GetDateTime()
{
return new DateTime(dateTicks);
}
/// <summary>
/// 시간 정보를 저장
/// </summary>
/// <param name="dateTime"></param>
public void SetDateTime(DateTime dateTime)
{
dateTicks = dateTime.Ticks;
}
}
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);
Init();
}
#endregion
[Header("Reference")]
[SerializeField] private GoogleAdMob _adMob;
// 캐릭터 가챠
private RewardInfo _dailyCharFreeGachaRewardInfo;
public RewardInfo DailyCharFreeGachaRewardInfo => _dailyCharFreeGachaRewardInfo;
private RewardInfo _dailyCharAdGachaRewardInfo;
public RewardInfo DailyCharAdGachaRewardInfo => _dailyCharAdGachaRewardInfo;
// 마법석 가챠
private RewardInfo _dailyStoneFreeGachaRewardInfo;
public RewardInfo DailyStoneFreeGachaRewardInfo => _dailyStoneFreeGachaRewardInfo;
private RewardInfo _dailyStoneAdGachaRewardInfo;
public RewardInfo DailyStoneAdGachaRewardInfo => _dailyStoneAdGachaRewardInfo;
// 상점
private DateTime _dailyShopResetTime;
public Action OnDailyGachaInfoChanged;
private void Init()
{
LoadDailyFreeGachaResetTimeInfo();
LoadAdGachaResetTimeInfo();
}
#region Data Load & Save
#region 일일 초기화(가챠 - 오전 6시 초기화)
/// <summary>
/// 일일 가챠 초기화 시간 및 횟수를 캐싱하여 저장하고,
/// 업데이트가 필요할 시 업데이트를 바로 진행.
/// </summary>
private void LoadDailyFreeGachaResetTimeInfo()
{
// TODO : DB에 저장된 [일일 무료 가챠] 시간 및 횟수 데이터를 가져와서 캐싱
// 테스트용: 오늘 아침 6시, 가챠횟수 1회
DateTime todayReset = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 6, 0, 0);
_dailyCharFreeGachaRewardInfo = new RewardInfo(todayReset.Ticks, 1);
_dailyStoneFreeGachaRewardInfo = new RewardInfo(todayReset.Ticks, 1);
if (_dailyCharFreeGachaRewardInfo.state == 0 && IsDailyResetTime(_dailyCharFreeGachaRewardInfo.GetDateTime()))
{
_dailyCharFreeGachaRewardInfo.state = 1;
// TODO : DB에 [일일 무료 가챠] 시간과 상태를 저장
}
if(_dailyStoneFreeGachaRewardInfo.state == 0 && IsDailyResetTime(_dailyStoneFreeGachaRewardInfo.GetDateTime()))
{
_dailyStoneFreeGachaRewardInfo.state = 1;
// TODO : DB에 [일일 무료 가챠] 시간과 상태를 저장
}
OnDailyGachaInfoChanged?.Invoke();
}
/// <summary>
/// 일일 무료 가챠 시간을 업데이트 - 횟수 사용 시
/// </summary>
public void UpdateDailyFreeGachaResetTimeInfo(GachaType type)
{
DateTime now = DateTime.Now;
DateTime todayReset = new DateTime(now.Year, now.Month, now.Day, 6, 0, 0);
DateTime nextResetDate = (now.Hour < 6) ? todayReset : todayReset.AddDays(1);
switch(type)
{
case GachaType.Char:
_dailyCharFreeGachaRewardInfo.SetDateTime(nextResetDate);
_dailyCharFreeGachaRewardInfo.state = 0;
// TODO : DB에 [일일 무료 가챠] 시간과 상태를 저장
break;
case GachaType.Stone:
_dailyStoneFreeGachaRewardInfo.SetDateTime(nextResetDate);
_dailyStoneFreeGachaRewardInfo.state = 0;
// TODO : DB에 [일일 무료 가챠] 시간과 상태를 저장
break;
}
OnDailyGachaInfoChanged?.Invoke();
}
#endregion
#region 12시간 초기화(가챠)
/// <summary>
/// 광고 가챠 시간 및 횟수를 캐싱하여 저장하고,
/// 업데이트가 필요할 시 바로 진행.
/// </summary>
private void LoadAdGachaResetTimeInfo()
{
// TODO : DB에 저장된 [광고 가챠] 시간 및 횟수 데이터를 가져와서 캐싱
// 테스트용 초기값: 11시간 전, 가챠 횟수 1회
_dailyCharAdGachaRewardInfo = new RewardInfo(DateTime.Now.AddHours(-11).AddMinutes(-59).Ticks, 1);
_dailyStoneAdGachaRewardInfo = new RewardInfo(DateTime.Now.AddHours(-11).AddMinutes(-59).Ticks, 1);
if (_dailyCharAdGachaRewardInfo.state < 2 && IsDailyCharAdGachaResetTime(out int stack))
{
_dailyCharAdGachaRewardInfo.state += stack;
if (_dailyCharAdGachaRewardInfo.state > 2) _dailyCharAdGachaRewardInfo.state = 2;
// TODO : DB에 [광고 가챠] 시간과 상태를 저장
}
if(_dailyStoneAdGachaRewardInfo.state < 2 && IsDailyCharAdGachaResetTime(out int stack2))
{
_dailyStoneAdGachaRewardInfo.state += stack2;
if (_dailyStoneAdGachaRewardInfo.state > 2) _dailyStoneAdGachaRewardInfo.state = 2;
// TODO : DB에 [광고 가챠] 시간과 상태를 저장
}
OnDailyGachaInfoChanged?.Invoke();
}
/// <summary>
/// 광고 가챠 횟수를 업데이트 - 횟수 사용 시
/// </summary>
public void UpdateAdGachaResetTimeInfo(GachaType type)
{
switch(type)
{
case GachaType.Char:
UpdateCharAdGachaResetTimeInfo();
break;
case GachaType.Stone:
UpdateStoneAdGachaResetTimeInfo();
break;
}
OnDailyGachaInfoChanged?.Invoke();
}
private void UpdateCharAdGachaResetTimeInfo()
{
if (_dailyCharAdGachaRewardInfo.state > 0)
{
// 해당 부분은 RandomGachaSystem으로 옮기는 게 적절해 보임
// 추후에 옮길 예정
if (_adMob.IsReady)
{
_adMob.LoadedAd.Show();
}
_dailyCharAdGachaRewardInfo.state -= 1;
// TODO : DB에 [광고 가챠] 시간과 상태를 저장
Debug.Log($"광고 가챠 스택 감소: {_dailyCharAdGachaRewardInfo.state}, 마지막 갱신: {_dailyCharAdGachaRewardInfo.GetDateTime()}");
}
}
private void UpdateStoneAdGachaResetTimeInfo()
{
if (_dailyStoneAdGachaRewardInfo.state > 0)
{
// 해당 부분은 RandomGachaSystem으로 옮기는 게 적절해 보임
// 추후에 옮길 예정
if (_adMob.IsReady)
{
_adMob.LoadedAd.Show();
}
_dailyStoneAdGachaRewardInfo.state -= 1;
// TODO : DB에 [광고 가챠] 시간과 상태를 저장
Debug.Log($"광고 가챠 스택 감소: {_dailyStoneAdGachaRewardInfo.state}, 마지막 갱신: {_dailyCharAdGachaRewardInfo.GetDateTime()}");
}
}
#endregion
#region 일일 초기화(상점)
// 상점의 경우 일일 초기화가 진행되는 시점인지 bool 여부만 판정하면 되므로
// 가챠확률 계산과는 로직을 다르게 설계했습니다.
// 만약 일일 퀘스트 등의 다른 컨텐츠도 초기화 시간이 같을 경우 이 함수로 전부 처리 가능합니다.
/// <summary>
/// 초기화가 되는 시점인지 확인하고 정보를 로드
/// </summary>
/// <param name="resetTime"></param>
/// <returns></returns>
public bool LoadDailyShopResetTime(out DateTime resetTime)
{
// TODO : DB에 저장된 [상점 초기화] 시간 데이터를 가져와서 캐싱
// _dailyShopResetTime = {상점 초기화 시간}
bool isResetTime = SaveDailyShopResetTime(_dailyShopResetTime);
resetTime = _dailyShopResetTime;
return isResetTime;
}
/// <summary>
/// 초기화가 되는 시점일 때 업데이트를 진행함
/// </summary>
/// <param name="lastTime"></param>
/// <returns></returns>
private bool SaveDailyShopResetTime(DateTime lastTime)
{
if (IsDailyResetTime(lastTime))
{
DateTime now = DateTime.Now;
DateTime todayReset = new DateTime(now.Year, now.Month, now.Day, 6, 0, 0);
if (now.Hour < 6)
{
_dailyShopResetTime = todayReset;
}
else
{
_dailyShopResetTime = todayReset.AddDays(1);
}
// TODO : DB에 [상점 초기화] 시간을 저장
return true;
}
return false;
}
#endregion
#endregion
#region Obtain 판정
#region 일일 가챠 가능 여부 판정
/// <summary>
/// 일일 가챠가 가능한 상태인지 판별함.
/// </summary>
/// <returns></returns>
public bool CanObtainedFreeGachaReward(GachaType type)
{
bool canObtain = false;
switch (type)
{
case GachaType.Char:
canObtain = CanObtainFreeCharGachaReward();
break;
case GachaType.Stone:
canObtain = CanObtainFreeStoneGachaReward();
break;
}
return canObtain;
}
private bool CanObtainFreeCharGachaReward()
{
if (_dailyCharFreeGachaRewardInfo.state == 1) return true;
if (IsDailyResetTime(_dailyCharFreeGachaRewardInfo.GetDateTime()))
{
_dailyCharFreeGachaRewardInfo.state = 1;
// TODO : DB에 [일일 무료 가챠] 시간과 상태를 저장
OnDailyGachaInfoChanged?.Invoke();
return true;
}
return false;
}
private bool CanObtainFreeStoneGachaReward()
{
if (_dailyStoneFreeGachaRewardInfo.state == 1) return true;
if (IsDailyResetTime(_dailyStoneFreeGachaRewardInfo.GetDateTime()))
{
_dailyStoneFreeGachaRewardInfo.state = 1;
// TODO : DB에 [일일 무료 가챠] 시간과 상태를 저장
OnDailyGachaInfoChanged?.Invoke();
return true;
}
return false;
}
/// <summary>
/// 마지막 저장 시간을 기점으로 초기화가 되는 시점인지 확인하는 함수.
/// 현재 시간이 마지막 저장 시간보다 미래면 true, 아니면 false.
/// </summary>
/// <param name="date"></param>
/// <returns></returns>
private bool IsDailyResetTime(DateTime date)
{
DateTime now = DateTime.Now;
if (now.Year > date.Year && now.Hour >= date.Hour) return true;
if (now.Year == date.Year && now.Month > date.Month && now.Hour >= date.Hour) return true;
if (now.Year == date.Year && now.Month == date.Month && now.Day > date.Day && now.Hour >= date.Hour) return true;
return false;
}
#endregion
#region 12시간 광고 가챠 가능 여부 판정
/// <summary>
/// 광고 가챠가 가능한 상태인지 판별함.
/// </summary>
/// <returns></returns>
public bool CanObtainAdGachaReward(GachaType type)
{
bool canObtain = false;
switch (type)
{
case GachaType.Char:
canObtain = CanObtainCharAdGachaReward();
break;
case GachaType.Stone:
canObtain = CanObtainStoneAdGachaReward();
break;
}
return canObtain;
}
private bool CanObtainCharAdGachaReward()
{
if (IsDailyCharAdGachaResetTime(out int stack))
{
_dailyCharAdGachaRewardInfo.state += stack;
if (_dailyCharAdGachaRewardInfo.state > 2) _dailyCharAdGachaRewardInfo.state = 2;
// TODO : DB에 시간과 상태를 저장
OnDailyGachaInfoChanged?.Invoke();
return true;
}
if (_dailyCharAdGachaRewardInfo.state >= 1) return true;
return false;
}
private bool CanObtainStoneAdGachaReward()
{
if (IsDailyStoneAdGachaResetTime(out int stack))
{
_dailyStoneAdGachaRewardInfo.state += stack;
if (_dailyStoneAdGachaRewardInfo.state > 2) _dailyStoneAdGachaRewardInfo.state = 2;
// TODO : DB에 시간과 상태를 저장
OnDailyGachaInfoChanged?.Invoke();
return true;
}
if (_dailyStoneAdGachaRewardInfo.state >= 1) return true;
return false;
}
/// <summary>
/// 12시간 단위 누적 스택 계산
/// </summary>
private bool IsDailyCharAdGachaResetTime(out int stack)
{
DateTime now = DateTime.Now;
DateTime lastTime = _dailyCharAdGachaRewardInfo.GetDateTime();
TimeSpan difference = now - lastTime;
stack = 0;
if (difference.TotalHours >= 12)
{
int stackCount = (int)(difference.TotalHours / 12);
stack = Mathf.Min(stackCount, 2); // 최대 2 스택
// 마지막 갱신 시간 이동
_dailyCharAdGachaRewardInfo.SetDateTime(lastTime.AddHours(12 * stack));
Debug.Log($"스택 증가: {stack}, 새로운 마지막 갱신 시간: {_dailyCharAdGachaRewardInfo.GetDateTime()}");
return true;
}
return false;
}
private bool IsDailyStoneAdGachaResetTime(out int stack)
{
DateTime now = DateTime.Now;
DateTime lastTime = _dailyStoneAdGachaRewardInfo.GetDateTime();
TimeSpan difference = now - lastTime;
stack = 0;
if (difference.TotalHours >= 12)
{
int stackCount = (int)(difference.TotalHours / 12);
stack = Mathf.Min(stackCount, 2); // 최대 2 스택
// 마지막 갱신 시간 이동
_dailyStoneAdGachaRewardInfo.SetDateTime(lastTime.AddHours(12 * stack));
Debug.Log($"스택 증가: {stack}, 새로운 마지막 갱신 시간: {_dailyStoneAdGachaRewardInfo.GetDateTime()}");
return true;
}
return false;
}
#endregion
#endregion
}
UI적 반영을 위해 다음과 같이 구성하였다.
using System;
using System.Collections;
using System.Data;
using System.Net.Http.Headers;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class GachaUIController : MonoBehaviour
{
[Header("CharAdButtonUI")]
[SerializeField] private Image[] _charAdImages;
[SerializeField] private GameObject _charAdCooltimeImage;
[SerializeField] private TMP_Text _charAdCooltimeText;
[Header("CharOneButtonUI")]
[SerializeField] private TMP_Text _charOneText;
[SerializeField] private GameObject _charFreeGacha;
[SerializeField] private GameObject _charConsumeGacha;
[SerializeField] private GameObject _charDailyCooltimeImage;
[SerializeField] private TMP_Text _charDailyCooltimeText;
[Header("StoneAdButtonUI")]
[SerializeField] private Image[] _stoneAdImages;
[SerializeField] private GameObject _stoneAdCooltimeImage;
[SerializeField] private TMP_Text _stoneAdCooltimeText;
[Header("StoneOneButtonUI")]
[SerializeField] private TMP_Text _stoneOneText;
[SerializeField] private GameObject _stoneFreeGacha;
[SerializeField] private GameObject _stoneConsumeGacha;
[SerializeField] private GameObject _stoneDailyCooltimeImage;
[SerializeField] private TMP_Text _stoneDailyCooltimeText;
private Coroutine _adCooltimeTimer;
private Coroutine _dailyCooltimeTimer;
private void Start()
{
UpdateUI();
}
#region Event
private void OnEnable()
{
if (TimeManager.Instance != null)
TimeManager.Instance.OnDailyGachaInfoChanged += UpdateUI;
StartAdTimer();
StartDailyTimer();
}
private void OnDisable()
{
TimeManager.Instance.OnDailyGachaInfoChanged -= UpdateUI;
StopAdTimer();
StopDailyTimer();
}
#endregion
#region AdButtonTimer
private void StartAdTimer()
{
if (_adCooltimeTimer != null)
{
StopCoroutine(_adCooltimeTimer);
}
_adCooltimeTimer = StartCoroutine(AdCooltimeCoroutine());
}
private void StopAdTimer()
{
if (_adCooltimeTimer != null)
{
StopCoroutine(_adCooltimeTimer);
_adCooltimeTimer = null;
}
}
#endregion
#region DailyButtonTimer
private void StartDailyTimer()
{
if (_dailyCooltimeTimer != null)
{
StopCoroutine(_dailyCooltimeTimer);
}
_dailyCooltimeTimer = StartCoroutine(DailyCooltimeCoroutine());
}
private void StopDailyTimer()
{
if (_dailyCooltimeTimer != null)
{
StopCoroutine(_dailyCooltimeTimer);
_dailyCooltimeTimer = null;
}
}
#endregion
#region UIUpdate
private void UpdateUI()
{
UpdateAdButton();
UpdateOneButton();
}
private void UpdateAdButton()
{
if (TimeManager.Instance != null)
{
switch (TimeManager.Instance.DailyCharAdGachaRewardInfo.state)
{
case 2:
_charAdImages[0].color = Color.white;
_charAdImages[1].color = Color.white;
_charAdCooltimeImage.gameObject.SetActive(false);
break;
case 1:
_charAdImages[0].color = Color.grey;
_charAdImages[1].color = Color.white;
_charAdCooltimeImage.gameObject.SetActive(true);
break;
case 0:
_charAdImages[0].color = Color.grey;
_charAdImages[1].color = Color.grey;
_charAdCooltimeImage.gameObject.SetActive(true);
break;
default:
break;
}
switch(TimeManager.Instance.DailyStoneAdGachaRewardInfo.state)
{
case 2:
_stoneAdImages[0].color = Color.white;
_stoneAdImages[1].color = Color.white;
_stoneAdCooltimeImage.gameObject.SetActive(false);
break;
case 1:
_stoneAdImages[0].color = Color.grey;
_stoneAdImages[1].color = Color.white;
_stoneAdCooltimeImage.gameObject.SetActive(true);
break;
case 0:
_stoneAdImages[0].color = Color.grey;
_stoneAdImages[1].color = Color.grey;
_stoneAdCooltimeImage.gameObject.SetActive(true);
break;
default:
break;
}
}
}
private void UpdateOneButton()
{
if (TimeManager.Instance != null)
{
if (TimeManager.Instance.DailyCharFreeGachaRewardInfo.state == 1)
{
_charFreeGacha.SetActive(true);
_charConsumeGacha.SetActive(false);
_charDailyCooltimeImage.gameObject.SetActive(false);
_charOneText.text = "일일 무료";
}
else
{
_charFreeGacha.SetActive(false);
_charConsumeGacha.SetActive(true);
_charDailyCooltimeImage.gameObject.SetActive(true);
_charOneText.text = "1회 뽑기";
}
if (TimeManager.Instance.DailyStoneFreeGachaRewardInfo.state == 1)
{
_stoneFreeGacha.SetActive(true);
_stoneConsumeGacha.SetActive(false);
_stoneDailyCooltimeImage.gameObject.SetActive(false);
_stoneOneText.text = "일일 무료";
}
else
{
_stoneFreeGacha.SetActive(false);
_stoneConsumeGacha.SetActive(true);
_stoneDailyCooltimeImage.gameObject.SetActive(true);
_stoneOneText.text = "1회 뽑기";
}
}
}
#endregion
private IEnumerator AdCooltimeCoroutine()
{
while (true)
{
if (TimeManager.Instance != null)
{
TimeManager.Instance.CanObtainAdGachaReward(GachaType.Char);
TimeManager.Instance.CanObtainAdGachaReward(GachaType.Stone);
DateTime now = DateTime.Now;
DateTime charLastTime = TimeManager.Instance.DailyCharAdGachaRewardInfo.GetDateTime();
TimeSpan charCooltime = charLastTime.AddHours(12) - now;
_charAdCooltimeText.text = $"다음 초기화 : {charCooltime.Hours}시간 {charCooltime.Minutes}분";
DateTime stoneLastTime = TimeManager.Instance.DailyStoneAdGachaRewardInfo.GetDateTime();
TimeSpan stoneCooltime = stoneLastTime.AddHours(12) - now;
_stoneAdCooltimeText.text = $"다음 초기화 : {stoneCooltime.Hours}시간 {stoneCooltime.Minutes}분";
}
UpdateAdButton();
yield return new WaitForSeconds(1);
}
}
private IEnumerator DailyCooltimeCoroutine()
{
while (true)
{
if (TimeManager.Instance != null)
{
TimeManager.Instance.CanObtainedFreeGachaReward(GachaType.Char);
TimeManager.Instance.CanObtainedFreeGachaReward(GachaType.Stone);
DateTime now = DateTime.Now;
DateTime charNextdate = TimeManager.Instance.DailyCharFreeGachaRewardInfo.GetDateTime();
TimeSpan charCooltime = charNextdate - now;
_charDailyCooltimeText.text = $"다음 초기화 : {charCooltime.Hours}시간 {charCooltime.Minutes}분";
DateTime stoneNextdate = TimeManager.Instance.DailyStoneFreeGachaRewardInfo.GetDateTime();
TimeSpan stoneCooltime = stoneNextdate - now;
_stoneDailyCooltimeText.text = $"다음 초기화 : {stoneCooltime.Hours}시간 {stoneCooltime.Minutes}분";
}
UpdateOneButton();
yield return new WaitForSeconds(1);
}
}
}
가챠 결과에 대한 각 슬롯의 UI 표시는 다음과 같이 구성했다.
using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class GachaResultUI : MonoBehaviour, IPointerClickHandler
{
[Header("Prefab")]
[SerializeField] private GameObject _gachaResultSlotUI;
[Header("UI Reference")]
[SerializeField] private Transform _content;
[Header("Icon Reference")]
[SerializeField] private Sprite _coinImage;
[SerializeField] private Sprite _diaImage;
[Header("Slots")]
[SerializeField] private Image[] _gachaResultImages;
private GameObject[] _slots = new GameObject[10];
public void HeroGachaUpdate(UnitData data, int index, string amount)
{
if (_slots[index] == null)
{
_slots[index] = Instantiate(_gachaResultSlotUI, _content);
}
GachaResultUISlot slot = _slots[index].GetComponent<GachaResultUISlot>();
slot.UpdateUI(data.Icon, amount);
}
public void StoneGachaUpdate(MagicStoneData data, int index, string amount)
{
if (_slots[index] == null)
{
_slots[index] = Instantiate(_gachaResultSlotUI, _content);
}
GachaResultUISlot slot = _slots[index].GetComponent<GachaResultUISlot>();
slot.UpdateUI(data.Icon, amount);
}
public void StoneGachaUpdate(MagicStoneRewardType type, int index, string amount)
{
if (_slots[index] == null)
{
_slots[index] = Instantiate(_gachaResultSlotUI, _content);
}
GachaResultUISlot slot = _slots[index].GetComponent<GachaResultUISlot>();
switch(type)
{
case MagicStoneRewardType.Gold500:
case MagicStoneRewardType.Gold1000:
case MagicStoneRewardType.Gold10000:
slot.UpdateUI(_coinImage, amount);
break;
case MagicStoneRewardType.Dia50:
case MagicStoneRewardType.Dia100:
case MagicStoneRewardType.Dia1000:
slot.UpdateUI(_diaImage, amount);
break;
}
}
// 비활성화와 동시에 슬롯을 한개만 남겨두고 전부 파괴(Grid UI를 위해서 임시 처리)
// 오브젝트 풀 반영할 수 있을 것 같습니다 -> 추후 풀 반영
private void OnDisable()
{
if (_slots.Length <= 1) return;
else
{
for (int i = 1; i < _slots.Length; i++)
{
Destroy(_slots[i]);
}
}
}
public void OnPointerClick(PointerEventData eventData)
{
gameObject.SetActive(false);
}
}