- 게임 오버 씬에서는 획득한 보상, 게임 내에서의 기록 등 점수가 나오고, 이후에 기록된 랭킹이 표시된다.
Player의 username을 받아와 PlayerData.json에 저장하기
-오큘러스를 사용하는 사용자는 오큘러스의 nickname이 존재한다.
- 시작할때, 이 nickname을 player의 username으로 자동 저장되게 한다.
=> 게임이 끝나면 username과 score를 정보로 저장해 firebase에 기록한다.
https://developer.oculus.com/documentation/unity/ps-setup/
Set Up for Platform Development with Unity: Unity | Oculus Developers
developer.oculus.com
- 위 링크에 따라 몇가지 셋팅이 필요하다.
https://developer.oculus.com/manage/app/api/
Oculus Developer Center | Authenticate
developer.oculus.com
-위 링크에서 oculus platform setting에 필요한 앱 ID를 설정할 수 있다.
-설정한 app ID를 oculus>Platform>Edit settings에 입력해준다.
-Unity Editor에서 Play를 눌러 사용자 정보를 테스트하기 위해서는 AppID를 입력하고, UseStandalone Platform을 체크해 로그인해야한다.
-로그인후에는 상단 이미지의 Currently usint the credentials~와 같은 안내창이 나오게 된다.
-빌드한 앱에서도 사용자를 받아오려면 다음과 같은 절차가 필요하다. data use certify가 필요하다.
-상단에 방문했던 링크(api링크)에서 수정할 수 있다.
-DeveloperHub의 App Distribution을 누르면 App을 선택할 수 있다.
-앱을 선택 후 ReleaseChannel의 우측에 있는 Upload를 누른 후 빌드파일을 Drag & Drop한다.
-Release Channel에 빌드파일을 업로드한 후, Users를 클릭하여 내 계정을 추가하였다.
-하단의 링크를 참고했다.
GetLoggedInUser returns Oculus ID 0 with v59 update
I have my build on three Quest 3 devices. Two are running: 59.0.0.163.706.533208642 The other is running: 57.0.0.297.669.526237896 All devices are using the same login account. When running GetLoggedInUser it returns the correct Oculus ID on v57, and Ocul
communityforums.atmeta.com
-이 때 unity build파일을 업로드 하고, 기기에 설치할 때 몇가지 주의사항이 있다.
1. key 셋팅 - 키가 설정되어있지 않은 경우 ReleaseChannel에 업로드할 수 없다.(Publish Settings> KeyManager)
2. 앱이 기기에 설치 되어있는 경우 - 앱을 uninstall하고 새로운 빌드apk를 설치해야한다.releaseChannel로 부터 앱을 다운받아 설치하려고 할 때 이미 기기에 설치되어있다면 제대로 설치가 안되는 오류가있다.
3. release Channel에 업로드할 때에는 Version과 version code를 변경 후 업로드해야한다. 같은 경우 업로드 불가하다.
-빌드 후 Android Logcat을 사용해 UserID와 DisplayName을 받아오는지 확인하였다.
Oculus Users.GetLoggedInUser() return empty string for DisplayName field
I am trying to get the userId, ImageURL, OculusID, and DisplayName for the local Oculus user in my Unity 3D game. I get correctly the userId, the ImageURL, and the OculusID, but the DisplayName is ...
stackoverflow.com
- 이 링크의 내용처럼 빌드 후에는 userID를 받은 후에 그것을 통해 한번 더 request해야 DisplayName을 가져올 수 있다.
-즉, unity Editor에서는 바로 가져올 수 있지만, 빌드시에는 요청이 한번 더 필요하다.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Firebase 사용
https://firebase.google.com/docs/unity/setup?hl=ko
Unity 프로젝트에 Firebase 추가 | Firebase for Unity
Firebase 데모 데이가 시작되었습니다. Google 최고의 기술을 활용하여 AI 기반 풀 스택 앱을 빌드하고 성장시키는 방법에 관한 데모를 시청하세요. 의견 보내기 Unity 프로젝트에 Firebase 추가 컬렉션
firebase.google.com
-먼저 프로젝트를 firebase와 연동해주자. 위 링크를 참고하도록한다.
데이터 저장
게임이 종료되었을 때 플레이어의 점수와 이름을 Fireabase에 저장해야한다.
-이 저장된 데이터를 포함하여 업데이트된 랭킹창을 띄운다.
-이제 플레이어의 정보를 가져왔으므로 이를 데이터로 저장해 firebase로 넘겨야한다.
=> firebase로 데이터는 어떤 순간에 넘어가야하는가? username과 score를 모두 받아오고 난 순간에 넘겨야한다.
-데이터가 잘 저장되는것을 확인했다. 그러나 현재는 중복된 값이 있어도 계속 새롭게 저장된다. 따라서 중복값인 경우에 최대점수이면 update하고, 아닌 경우에는 저장하지 않도록 해야한다.
-코드를 수정해 user가 있는지 확인하고 없다면 rank 기록을 새로 작성하도록 하였다.
-기록이 있다면, 새로 획득한 점수가 큰 경우에 변경된다.
데이터 불러오기
-데이터를 저장할 수 있게되었으니, firebase로부터 불러올 수도 있어야 한다.
-데이터는 어떤 때 불러와야하는가?
=> 저장 한 후, rank가 보여질 스크롤 뷰가 setActive되기 전에 불러와야한다.
=> 즉, 저장하고 바로 불러오게 하면 된다.
스크롤뷰 생성 및 연동
https://meltingmelvin.tistory.com/108
[UGUI연습] 미션(동적 스크롤뷰 활용)
빈오브젝트 (content) 만들고 앵커프리셋 시프트 + 알트 좌상단 컴포넌트 Content Size Fitter 붙이고 스크롤뷰에 ScrollRect붙이고 Vertical 만 체크, scrollrect에 content를 넣어준다.스크롤 뷰에 마스크 추가 -
meltingmelvin.tistory.com
-게임 오버씬과 게임클리어씬이 필요하다.
-랭킹은 기존에 생성된 정보들이 다 보여지고 난 후, 마지막에 보여져야하므로 꺼두었다가 활성화 되도록한다.
-onRankActive에서 랭크캔버스가 활성화되고 코루틴을 통해 데이터를 가져온다.
-이 때, onLoadFirebaseData를 통해 랭킹 데이터를 가져오도록 한다.
-GetUser의 Text와 PlayerRankText에 각각 할당해준다.
-Text에는 랭킹 텍스트가, PlayerRankText에는 유저의 랭킹을 알려주는 텍스트가 뜨게된다.
구현결과
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Oculus.Platform;
using Oculus.Platform.Models;
using System.Linq;
using TMPro;
using Firebase;
using Firebase.Database;
public class GetUser : MonoBehaviour
{
class Rank
{
public string name;
public int score;
public Rank(string name, int score)
{
this.name = name;
this.score = score;
}
}
public DatabaseReference reference { get; set; }
// 라이브러리를 통해 불러온 FirebaseDatabase 관련객체를 선언해서 사용
private string leaderboardData = "";
private string playerRankData = "";
private int rank;
public int score;
public string OculusUserName= "";
private ulong userId;
private System.Action onGetUserName;
private System.Action onLoadFirebaseData;
public System.Action onRankActive;
private Dictionary<string, int> sortRank = new Dictionary<string, int>();
// [SerializeField] GameObject cellGo;
//[SerializeField] GameObject contentGo;
[SerializeField] TextMeshProUGUI text;
[SerializeField] TextMeshProUGUI playerRankText;
[SerializeField] Canvas rankCanvas;
private void Awake()
{
Core.Initialize();
//this.score = 0;
this.score = InfoManager.Instance.GetPlayerInfo().maxScore;
}
void Start()
{
//GameObject go = Instantiate(this.cellGo, this.contentGo.transform);//scrollview의 content의 자식으로 cell생성
Oculus.Platform.Entitlements.IsUserEntitledToApplication().OnComplete(EntitlementCallback);
this.getLoggedInUser();
this.onGetUserName = () => {
var reference = FirebaseDatabase.DefaultInstance.RootReference;
reference.Child("rank").OrderByChild("name").EqualTo(this.OculusUserName).GetValueAsync().ContinueWith(task =>
{
if (task.IsCompleted)
{
DataSnapshot snapshot = task.Result;
if (snapshot.Exists)
{//이미 user의 기록이 존재하는 경우
Debug.Log("user score exist");
foreach (var data in snapshot.Children)
{
IDictionary rank = (IDictionary)data.Value;
int databaseScore = int.Parse(rank["score"].ToString());
// if (databaseScore <= this.score)
{//새로운 점수가 기록된 점수보다 값이 크다면
// Debug.Log(rank["score"]);
Rank rank2 = new Rank(this.OculusUserName, this.score);
string json = JsonUtility.ToJson(rank2);//데이터를 json형태로 반환
string key = data.Key;
//root의 자식rank에 key 값 추가
reference.Child("rank").Child(key).SetRawJsonValueAsync(json);//생성된 키의 자식으로 json 데이터를 삽입
//
// Debug.Log("이름: " + rank["name"] + ", 점수: " + rank["score"]);
}
}
}
else
{
Debug.Log("user's record doesn't exist!");
Rank rank = new Rank(this.OculusUserName, score);
string json = JsonUtility.ToJson(rank);//데이터를 json형태로 반환
string key = reference.Child("rank").Push().Key;
//root의 자식rank에 key 값 추가
reference.Child("rank").Child(key).SetRawJsonValueAsync(json);//생성된 키의 자식으로 json 데이터를 삽입
}
}
});
};
this.onLoadFirebaseData = () =>
{
// string str = "";
var query = FirebaseDatabase.DefaultInstance.GetReference("rank").OrderByChild("score");
query.GetValueAsync().ContinueWith(task =>
{
if (task.IsCompleted)
{ // 성공적으로 데이터를 가져왔으면
Debug.Log("loaded");
DataSnapshot snapshot = task.Result;
// 데이터를 출력하고자 할때는 Snapshot 객체 사용함
int count = (int)snapshot.ChildrenCount+1;
//string leaderboardData = "";
foreach (DataSnapshot data in snapshot.Children)
{
IDictionary rank = (IDictionary)data.Value;
count--;
Debug.LogFormat("이름: {0},점수: {1}, count:{2}", rank["name"], rank["score"],count);
// StartCoroutine(this.CoWait());
string username = rank["name"].ToString();
string score = rank["score"].ToString();
this.leaderboardData += " "+count+" 이름: "+username+" 점수: "+score+"\n\n";
if (this.OculusUserName == rank["name"].ToString())
{
this.rank = count;
Debug.LogFormat("Player's rank is {0}", this.rank);
this.playerRankData += "Your Rank : "+count;
//GameObject go = Instantiate(this.cellGo, this.contentGo.transform);//scrollview의 content의 자식으로 cell생성
}
}
}
});
};
this.onRankActive = () => {
this.rankCanvas.gameObject.SetActive(true);
StartCoroutine(this.CoLoadData());
};
}
private IEnumerator CoLoadData()
{
yield return new WaitForSeconds(0f);
this.onLoadFirebaseData();
}
private void SortRank()
{
var sortRank = this.sortRank.OrderByDescending(rank => rank);
foreach(var data in sortRank)
{
Debug.LogFormat("Data: {0}",data.Key);
}
//Debug.Log()
}
void Update()
{
this.text.text = this.leaderboardData;
this.playerRankText.text = this.playerRankData;
}
void getLoggedInUser()
{
Users.GetLoggedInUser().OnComplete(getUserCallback);
}
void getUserCallback(Message<User> msg)
{
if (!msg.IsError)
{
User user = msg.Data;
Debug.LogFormat("UserID: {0},DisplayName : {1}",user.ID,user.DisplayName);
this.OculusUserName = user.DisplayName;
Users.Get(msg.Data.ID).OnComplete(message =>
{
if (!message.IsError)
{
Oculus.Platform.Models.User user = message.GetUser();
this.OculusUserName = user.DisplayName;
Debug.LogFormat("UserID2: {0},DisplayName : {1}", user.ID, user.DisplayName);
this.onGetUserName();
//StartCoroutine(this.CoLoadData());
}
else
{
var e = message.GetError();
}
});
}
else
{
Error error = msg.GetError();
}
}
void EntitlementCallback(Message msg)
{
if (msg.IsError) // User failed entitlement check
{
// Implements a default behavior for an entitlement check failure -- log the failure and exit the app.
Debug.LogError("You are NOT entitled to use this app.");
UnityEngine.Application.Quit();
}
else // User passed entitlement check
{
// Log the succeeded entitlement check for debugging.
Debug.Log("You are entitled to use this app.");
}
}
}
'[VR] GroundZero 개발' 카테고리의 다른 글
GroundZero 최종 정리 (0) | 2024.02.01 |
---|---|
[4Idle - GroundZero] damage text의 애니메이션 효과 및 연출 추가 (0) | 2024.01.12 |
[4Idle - GroundZero] startScene - LobbyScene 연결 및 startScene 수정 (0) | 2024.01.11 |
[4Idle - GroundZero] Player 사망 연출 게임씬에 적용 (1) | 2024.01.09 |
[4Idle - GroundZero] Enemy Animation & attack 오브젝트 수정 (0) | 2024.01.08 |