이번주는 Playfab에서 사용자 데이터를 등록해 관리하고 요청을 보내 Playfab 서버의 데이터를 불러오거나 수정하는 예제를 만들어보았다. Playfab을 사용하면 사용자 데이터나 아이템 수량 관련 데이터를 local 데이터베이스가 아닌 서버에서 관리할 수 있게 도와준다.
데이터 관리
My Game > Players > Player 하나 선택 > Statistics에서 정보를 확인할 수 있다. 각 Player가 가지고 있는 특정 int value를 Statistics에 등록하고 수치를 관리할 수 있다.
Statistics를 사용하기 위해서는 약간의 설정이 필요하다.
PlayFab API 설정
- My Game 오른쪽 톱니바퀴 > Title Settings > API Features > 아래로 스크롤해서 Allow client to post player statistics 체크
- 아래에서 Save 누르기
Statistics 활용
아이템 획득할 때마다 정보 기록
- PlayFab 서버에 정보를 업데이트 한다.
- PlayerStatisticsRequest를 사용해 아이템을 획득했을 때 아이템의 이름과 개수를 업데이트한다.
using PlayFab;
using PlayFab.ClientModels;
public class ItemObjNetwork : MonoBehaviour
{
//...
if (other.GetComponent<PhotonView>().IsMine)
{
var request = new UpdatePlayerStatisticsRequest
{
Statistics = new List<StatisticUpdate> {
new StatisticUpdate { StatisticName = item.itemName, Value = 1 }
}
};
PlayFabClientAPI.UpdatePlayerStatistics(
request,
(result) => { Debug.Log("Data Saved."); },
(error) => { Debug.Log("Saving Failed."); }
);
}
}
로그인 시 Statistics에서 정보 불러오기
Statistics는 int만 저장 가능하다.
- PlayFabClientAPI.GetPlayerStatistics( request, 성공 시 callback, 실패 시 callback )
- callback은 함수 또는 람다식으로 작성 가능
using UnityEngine;
using UnityEngine.UI;
using PlayFab;
using PlayFab.ClientModels;
using Photon.Pun;
using Photon.Realtime;
public class NetworkManager : MonoBehaviourPunCallbacks
{
//...
private void OnLoginSuccess(LoginResult result)
{
Debug.Log("Congratulations, you made your first successful API call!");
loginPanel.SetActive(false);
selectPanel.SetActive(true);
var request = new GetAccountInfoRequest { Email = emailInput.text };
PlayFabClientAPI.GetAccountInfo(request, GetAccountSuccess, GetAccountFail);
PlayFabClientAPI.GetPlayerStatistics(
new GetPlayerStatisticsRequest(),
(result) => {
foreach (var stat in result.Statistics)
{
Data.invenDict.Add(stat.StatisticName, stat.Value);
}
foreach (var item in Data.invenDict)
{
Debug.Log(item.Key);
}
},
(error) => { Debug.Log("LoadFailed"); }
);
// Connect to Network after login was successful
PhotonNetwork.ConnectUsingSettings();
}
}
Player Data (Title)
- 현재 게임(title)에서 사용할 정보 관리
- PlayFab의 Player Data는 string만 받음. 아마도 json으로 보내서 그런 것이 아닐까.
- 지역명 같은 것 저장 가능. 레벨이나 경험치 같은 숫자 → ToString() → 보내기 했다가 다시 받을 때 int.Parse()나 System.Convert.ToInt32() 사용해서 변환해 받는다.
Player Data (Publisher) 와의 차이
- 현재 게임(title)뿐 아니라 다른 게임(title)에도 적용할 공통 정보 설정
using UnityEngine;
using UnityEngine.UI;
using PlayFab;
using PlayFab.ClientModels;
using Photon.Pun;
using Photon.Realtime;
public class NetworkManager : MonoBehaviourPunCallbacks
{
//...
private void OnLoginSuccess(LoginResult result)
{
Debug.Log("Congratulations, you made your first successful API call!");
loginPanel.SetActive(false);
selectPanel.SetActive(true);
var request = new GetAccountInfoRequest { Email = emailInput.text };
PlayFabClientAPI.GetAccountInfo(request, GetAccountSuccess, GetAccountFail);
// Player Title
var userRequest = new UpdateUserDataRequest()
{
Data = new Dictionary<string, string>() { { item.itemName, 1.ToString() }, }
};
PlayFabClientAPI.UpdateUserData(userRequest,
(result) => { Debug.Log("Data Saved."); },
(error) => { Debug.Log("Save Failed."); }
);
// Connect to Network after login was successful
PhotonNetwork.ConnectUsingSettings();
}
}
Inventory
카탈로그
My Game > Economy > 카탈로그 생성
Display name 눌러서 기본으로 만들어진 아이템을 수정하거나 오른쪽 상단 New Item을 눌러서 새로 아이템을 만들 수 있다.
- By count 보통은 1로 설정
- 소비 대상인 아이템 (ex. 포션) Consumable로 설정
- 기간제 아이템은 By time 값을 설정한다.
- Is Stackable을 설정할 경우 아이템을 계속해서 쌓을 수 있다.
가상 통화
My Game > Economy > New Currency 에서 가상 통화 설정 가능
- Currency code 대문자 2글자
- Display name
- Deposit 처음에 부여할 돈의 양 설정 가능
아마도 국가별로 재화 가격을 다르게 매겨야해서 이런 시스템 만들어놓은 듯하다.
PurchaseItemRequest
Currency 이용해 아이템 구매와 관련된 request 보내기. Virtual Currency를 지정하고 적절한 Value를 지정하면 Currency에서 설정한 Deposit에서 구매한 아이템의 Value가 깎여 저장되고 아이템 개수는 1 증가할 것이다.
PurchaseRequest를 만들고 Request를 이용해 PlayFabClientAPI.PurchaseItem( 만든 구매 request, 요청 성공 시 실패 내용, 실패 시 실행 내용 )으로 설정한다.
using UnityEngine;
using Photon.Pun;
using PlayFab;
using PlayFab.ClientModels;
public class ItemObjNetwork : MonoBehaviour
{
//...
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
pv.RPC("GetItem", RpcTarget.All);
if (other.GetComponent<PhotonView>().IsMine)
{
inven = other.transform.Find("InventoryCanvas").GetComponent<Inventory>();
inven.GetItem(gameObject, item);
// Player Title
var userRequest = new UpdateUserDataRequest()
{
Data = new Dictionary<string, string>() { { item.itemName, 1.ToString() }, }
};
PlayFabClientAPI.UpdateUserData(userRequest,
(result) => { Debug.Log("Data Saved."); },
(error) => { Debug.Log("Save Failed."); }
);
var purchaceRequest = new PurchaseItemRequest()
{
ItemId = item.itemName, // PlayFab에서 설정한 item id가 숫자로 되어 있다면 item Name이 아니라 다른 방식으로 관리해야 할 것
VirtualCurrency = "KR",
Price = 0
};
PlayFabClientAPI.PurchaseItem(
purchaceRequest,
(result) => { Debug.Log("ok"); },
(error) => { Debug.Log("Fail to access an item."); }
);
Debug.Log(item.itemName + " Got!");
}
}
}
[PunRPC]
public void GetItem()
{
if (pv.IsMine) PhotonNetwork.Destroy(pv); // item owner : Master Client
}
}
아이템 소비
인벤토리 받아오기
각 아이템의 instance id를 알기 위해 inventory를 받아오면 편하다.
PlayFabClientAPI.GetUserInventory(request, 성공 시 실행 내용, 실패 시 실행 내용)
//NetworkManager.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using PlayFab;
using PlayFab.ClientModels;
using Photon.Pun;
using Photon.Realtime;
public class NetworkManager : MonoBehaviourPunCallbacks
{
List<ItemInstance> invenFromServer = new List<ItemInstance>();
private void OnLoginSuccess(LoginResult result)
{
//...
// Get Inventory
PlayFabClientAPI.GetUserInventory(
new GetUserInventoryRequest(),
(result) => {
for (int i = 0; i < result.Inventory.Count; i++)
{
ItemInstance item = result.Inventory[i];
Debug.Log($"{item.ItemId} / Count: {item.RemainingUses} / Instance ID: {item.ItemInstanceId}");
}
},
(error) => {
Debug.Log("Failed to get your inventory from the server.");
}
);
}
}
아이템 소모
Ditto라는 이름의 아이템을 소비하는 예제이다. ConsumeItemRequest를 만들고 PlayFabClientAPI.ConsumeItem( 만든 소비 request, 요청 성공 시 실행 내용, 실패 시 실행 내용) 을 적어준다.
using System.Collections.Generic;
using UnityEngine;
using PlayFab;
using PlayFab.ClientModels;
public class ItemEffect : MonoBehaviour
{
//...
public void UseItem(ItemScriptable _itemScriptable)
{
if(_itemScriptable.itemName == "Ditto")
{
var request = new ConsumeItemRequest { ConsumeCount = 1, ItemInstanceId = "" };
PlayFabClientAPI.ConsumeItem(request, (result) => { Debug.Log("used"); }, (error) => { Debug.Log("failed"); });
}
}
}
후기
PlayFab은 기본적인 네트워크 동작 방식을 알고 있으면 훨씬 수월하게 이해할 수 있을 것 같다. 처음에는 대체 뭔 소린고 했는데 이제보니 request를 만들고 request에 대한 응답에 따라 실행할 결과를 달리 주는 것이 딱 프런트/백 웹개발이랑 비슷하다. 한국어 자료가 그리 많지는 않은 듯하고 사용하려면 외국 유튜브나 게시물을 많이 참고해야 할 듯하다. 아니면 아예 파이어베이스를 쓰든가... 어쨌든 이번 기회에 맛보기로 배워볼 수 있어서 좋았다!
알고리즘 스터디도 했고 마우스 드래그 미니게임도 완성했으나 이번주는 정리가 조금 덜 되어서 수업 내용만 간단히 정리해보았다. 이번주 말까지 사이드 프로젝트 (백엔드 개발) 를 마무리할 예정인데 배포까지 할 수 있었으면 좋겠다. ㅠㅠ
유데미코리아 바로가기 : https://bit.ly/3b8JGeD
본 포스팅은 유데미-웅진씽크빅 취업 부트캠프 유니티 1기 과정 후기로 작성되었습니다.
새로운 가능성의 시작, 유데미 x 웅진씽크빅
글로벌 최신 IT 기술과 실무 교육을 입문부터 심화까지! 프로그래밍, 인공지능, 데이터, 마케팅, 디자인 등 세계 최고의 강의를 경험하세요.
www.udemykorea.com
댓글