1. 오늘 알아볼 내용
유저가 보유한 재화를 GamingServices에서 로드한 뒤에 UI에 표시하는 내용에 대해 다룹니다.
- 유저가 보유한 재화를 Economy 에서 로드하는 방법
- 로드 중 발생한 에러를 처리하는 방법
- Economy 에서 데이터를 로드한 후 UI에 표시하는 방법
2. 유저가 보유한 재화 데이터 로드
2-1 선행학습
2-1-1 유저의 재화 데이터 로드 요청
var options = new GetBalancesOptions { ItemsPerFetch = 100 };
return EconomyService.Instance.PlayerBalances.GetBalancesAsync(options);
GetBalancesOptions | 한번에 로드할 목록의 수이다. 위 예제는 데이터를 로드할 때 100개씩 로드한다. 기본 값은 20이며, 최대 100까지 입력할 수 있다. |
PlayerBalances | 플레이어의 통화 잔액을 가져오고 업데이트하기 위한 모든 메서드가 포함되어 있다 |
PlayerBalances.GetBalancesAsync(options) | 유저가 보유한 재화들을 로드한다. |
await getBalancesResult.GetNextAsync(options.ItemsPerFetch); 로 데이터를 추가로 더 로드할 수 있다.
GetBalancesOptions options = new GetBalancesOptions
{
ItemsPerFetch = 5
};
GetBalancesResult getBalancesResult = await EconomyService.Instance.PlayerBalances.GetBalancesAsync(options);
List<PlayerBalance> firstFiveBalances = getBalancesResult.Balances;
if (getBalancesResult.HasNext) {
// 추가로 로드하는 코드이다. GetNextAsync
getBalancesResult = await getBalancesResult.GetNextAsync(options.ItemsPerFetch);
List<PlayerBalance> nextFiveBalances = getBalancesResult.Balances;
}
2-2 스크립트 작업
2-2-1 EconomyManager.cs
Economy에게 유저가 보유한 재화를 로드하라고 요청하는 코드를 작성하겠습니다. EconomyManager 클래스에 아래의 전역변수와 함수를 추가합니다.
// EconomyManager.cs
public async Task RefreshCurrencyBalances()
{
GetBalancesResult balanceResult = null;
balanceResult = await GetEconomyBalances();
if (this == null) return;
}
static Task<GetBalancesResult> GetEconomyBalances()
{
var options = new GetBalancesOptions { ItemsPerFetch = 100 };
return EconomyService.Instance.PlayerBalances.GetBalancesAsync(options);
}
2-2-2 ABTestLevelDifficultySceneManager.cs
유저가 로그인을 완료하면 GamingServices에게 데이터 로드를 요청하는 코드를 작성한다.
// ABTestLevelDifficultySceneManager.cs
async Task LoadDataFromServices()
{
// -- 경제 구성요소 새로고침 관련 코드 생략
await LoadServicesData();
if (this == null) return;
}
// GamingServices로 부터 데이터 로드를 요청한다.
async Task LoadServicesData()
{
EconomyManager.instance.RefreshCurrencyBalances();
}
3. 로드한 데이터를 UI에 표시하기
재화의 데이터를 표시하는 UI는 CurrencyItemView 클래스에서 관리하고 있다.
각각의 CurrencyItemView 는 CurrencyHudView 클래스에서 관리하고 있다.
3-1 스크립트 작성
3-1-1 EconomyManager.cs
EconomyManager 클래스에서 유저의 재화 데이터를 로드하면 CurrencyHudView 클래스에게 로드한 데이터를 UI에 표시하라고 요청하는 코드를 작성한다.
// EconomyManager.cs
// 전역 변수 추가
public CurrencyHudView currencyHudView;
public async Task RefreshCurrencyBalances()
{
// -- 재화 데이터 로드 관련 코드 생략
// 데이터 로드가 완료되면 데이터를 UI에 표시한다.
currencyHudView.SetBalances(balanceResult);
}
3-2 테스트
유니티로 돌아가 재생 버튼을 누르면 화면 상단에 Coin 개수가 표시되는 걸 확인할 수 있다.
4. 데이터 로드 에러 처리
서버로 부터 데이터를 로드하므로 클라이언트 외부의 문제로 에러가 발생할 수 있다. 예를 들면 네트워크 환경이 좋지 않거나 데이터 로드 횟수 초과 등을 꼽을 수 있다. 이러한 에러를 처리하는 방법에 대해 알아보자.
참고로 에러 관련 코드는 깊게 분석하지 않았다. 프로젝트 만들때 그냥 복붙할 생각을 하고 있다. 유저가 어떤 이유로 에러가 생겼는지 알 수 있게 디버그로그 처리된 부분을 팝업창으로 변경할 생각하고 있다.
4-1 스크립트 작성
4-1-1 CancellationTokenHelper.cs
Assets\Common\Scripts 폴더에 CancellationTokenHelper.cs를 만들고 아래의 코드를 작성한다.
using System;
using System.Threading;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Unity.Services.Samples
{
// See Microsoft's CancellationTokenSource docs
// (https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=net-6.0)
// for more information about its purpose and functioning.
public class CancellationTokenHelper : IDisposable
{
CancellationTokenSource m_CancellationTokenSource;
bool m_Disposed;
public CancellationToken cancellationToken => m_CancellationTokenSource.Token;
public CancellationTokenHelper()
{
m_CancellationTokenSource = new CancellationTokenSource();
#if UNITY_EDITOR
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
#endif
}
#if UNITY_EDITOR
void OnPlayModeStateChanged(PlayModeStateChange playModeStateChange)
{
if (playModeStateChange == PlayModeStateChange.ExitingPlayMode)
{
m_CancellationTokenSource?.Cancel();
}
}
#endif
// IDisposable related implementation modeled after
// example code at https://learn.microsoft.com/en-us/dotnet/api/system.idisposable?view=net-6.0
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
void Dispose(bool triggeredByUserCode)
{
if (m_Disposed)
{
return;
}
// If triggeredByUserCode equals true, dispose both managed and unmanaged resources.
if (triggeredByUserCode)
{
// Dispose managed resources.
m_CancellationTokenSource.Dispose();
m_CancellationTokenSource = null;
}
#if UNITY_EDITOR
// Clean up unmanaged resources.
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
#endif
m_Disposed = true;
}
~CancellationTokenHelper()
{
Dispose(false);
}
}
}
4-1-2 Utils.cs
Assets\Common\Scripts 폴더에 Utils.cs를 만들고 아래의 코드를 작성한다.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
namespace Unity.Services.Samples
{
public static class Utils
{
public static async Task<T> RetryEconomyFunction<T>(Func<Task<T>> functionToRetry, int retryAfterSeconds)
{
if (retryAfterSeconds > 60)
{
Debug.Log($"Economy returned a rate limit exception with an extended Retry After time " +
$"of {retryAfterSeconds} seconds. Suggest manually retrying at a later time.");
return default;
}
Debug.Log($"Economy returned a rate limit exception. Retrying after {retryAfterSeconds} seconds");
try
{
// CancellationToken을 사용하면 지연 시간을 기다리는 동안 재생 모드를 종료하면
// Task.Delay가 취소되도록 할 수 있습니다.
// 그렇지 않으면 재생 모드 밖에서도 이 코드의 나머지 부분을 계속 실행하려고 시도할 것입니다.
using (var cancellationTokenHelper = new CancellationTokenHelper())
{
var cancellationToken = cancellationTokenHelper.cancellationToken;
await Task.Delay(retryAfterSeconds * 1000, cancellationToken);
// Call the function that we passed in to this method after the retry after time period has passed.
var result = await functionToRetry();
if (cancellationToken.IsCancellationRequested)
{
return default;
}
Debug.Log("Economy retry successfully completed");
return result;
}
}
catch (OperationCanceledException)
{
return default;
}
catch (Exception e)
{
Debug.LogException(e);
}
return default;
}
}
}
4-1-3 EconomyManager.cs 수정
재화 데이터 로드를 요청하는 RefreshCurrencyBalances() 를 수정한다.
// EconomyManager.cs
public async Task RefreshCurrencyBalances()
{
GetBalancesResult balanceResult = null;
try
{
balanceResult = await GetEconomyBalances();
}
catch (EconomyRateLimitedException e)
{
balanceResult = await Utils.RetryEconomyFunction(GetEconomyBalances, e.RetryAfter);
}
catch (Exception e)
{
// 아래의 코드를 팝업창에 띄워 유저가 어떤 에러가 발생했는지 알 수 있게 한다.
// 팝업창에 RefreshCurrencyBalances()를 요청하는 버튼을 만들어두는 것도 좋다.
Debug.Log("Problem getting Economy currency balances:");
Debug.LogException(e);
}
if (this == null) return;
// -- UI 표시 관련 코드 생략
}
5. 로그아웃과 함께 유저 재화 UI 정보 갱신
로그아웃하면 현재 계정의 재화 금액이 UI에 표시되지 않드록 UI를 갱신해줘야 합니다.
5-1 스크립트 작업
5-1-1 EconomyManager.cs 수정
아래의 함수를 EconomyManager.cs 에 추가합니다.
// EconomyManager.cs
public void ClearCurrencyBalances()
{
currencyHudView.ClearBalances();
}
5-1-2 ABTestLevelDifficultySceneManager.cs 수정
ABTestLevelDifficultySceneManager.SignOut 에서 로그아웃하면 위의 ClearCurrencyBalances를 호출하도록 함수를 수정합니다.
// ABTestLevelDifficultySceneManager.cs
void SignOut()
{
if (AuthenticationService.Instance.IsSignedIn)
{
EconomyManager.instance.ClearCurrencyBalances();
// -- 계정 로그아웃 코드 관련 생략
// UpdateSceneViewAfterSignOut();
}
}
# 제가 깜빡하고 경제 데이터를 클리어한 뒤에 UI를 갱신하는 코드를 빼 먹었습니다. 관련 코드는 다음 게시글에 올리겠습니다.
오늘은 여기까지!
'Unity 자습서 > GamingServices' 카테고리의 다른 글
Gamingservices - ABTestSample #7 Game Overrides 설정 (0) | 2023.03.01 |
---|---|
Gamingservices - ABTestSample #6 Remote Key 만들기 (0) | 2023.02.28 |
Gamingservices - ABTestSample #4 재화 만들기 (0) | 2023.02.25 |
Gamingservices - ABTestSample #3 로그아웃과 신규 계정 생성 (0) | 2023.02.25 |
댓글