승 수가 가장 높은 10명을 출력하는 리더보드를 만들어보자
데이터베이스에서 값을 불러 올 때, 정렬과 필터링을 사용해서 가져온다
1. OrderByChild("win") : int형인 승리 수를 기준으로 정렬한다.
2. LimitToLast(10) : 정렬된 결과 값에서 가장 마지막에 있는 10개의 결과값을 가져온다.
정렬은 늘 오름차순으로 되기 때문에, LimitToLast를 하게 되면 스냅샷의 값은 순서대로 1등~ 10등이 된다. 즉, 맨 마지막 결과값부터 가져오게 된다.
dbRef.Child("users").OrderByChild("win").LimitToFirst(10).GetValueAsync().ContinueWithOnMainThread(task =>
{
if (task.IsCanceled)
{
Debug.LogWarning("값 불러오기 취소");
return;
}
if (task.IsFaulted)
{
string error = task.Exception?.InnerException?.Message;
Debug.LogWarning($"값 불러오기 실패{error}");
return;
}
DataSnapshot snapshot = task.Result;
// 이후는 가져온 결과값으로 처리하기
}
데이터베이스에서 가져온 결과값을 저장하고 리더보드를 만든다
각 유저의 정보를 저장할 클래스를 만든다. 이름, 승 수, 승률을 가지고 있다.
public class LeaderBoardEntry
{
public string nickName;
public int win;
public float winRate;
public LeaderBoardEntry(string nickName, int win, float winRate)
{
this.nickName = nickName;
this.win = win;
this.winRate = winRate;
}
}
LeaderBoardEntry를 리스트로 가지는 클래스. 1위부터 10위까지의 정보를 모두 들고 있게 된다.
public class LeaderBoard
{
// 1위부터 10위까지의 정보를 리스트로 가지고 있다.
public List<LeaderBoardEntry> ranker;
// 초기화 작업
public void Init()
{
ranker = new List<LeaderBoardEntry>();
}
// 리스트에 유저를 추가한다.
public void ListUp(string nickName, int win, float winRate)
{
LeaderBoardEntry entry = new LeaderBoardEntry(nickName,win,winRate);
ranker.Add(entry);
}
}

".indexOn" 색인을 통해서 더욱 빠르게 데이터를 가져올 수 있다. 데이터 베이스에 저장되는 값들이 색인을 통해 정리되면서 저장된다.
값을 가져오는 것 또한 정리된 채로 들여오게 된다.
데이터가 전부 넘어오지 않는 문제가 있다. 이유를 알 수 없음.UID들의 정보들이 단일화 된 자료구조가 아니라서 못 가져오는 것이라 판단된다.
public static void GetLeaderboard()
{
dbRef.Child("users").OrderByChild("wins").LimitToLast(10).GetValueAsync().ContinueWithOnMainThread(task =>
{
if (task.IsCanceled)
{
Debug.LogWarning("값 불러오기 취소");
return;
}
if (task.IsFaulted)
{
string error = task.Exception?.InnerException?.Message;
Debug.LogWarning($"값 불러오기 실패{error}");
return;
}
DataSnapshot snapshot = task.Result;
LeaderBoard.ranker = new List<LeaderBoardEntry>();
LeaderBoard.ranker.Clear();
Debug.Log("여기는 들어옴"); //여기 들어오는것 확인 됨
int index = 0;
foreach (var entry in snapshot.Children)
{
string nickname;
if (entry.Child("nickname").Exists)
{
nickname = entry.Child("nickname").Value.ToString();
}
else
{
nickname = "Unknown";
}
int win;
if (entry.Child("wins").Exists)
{
win = (int)(long)entry.Child("wins").Value;
}
else
{
win = 0;
}
float winRate = 0f;
if (entry.Child("winRate").Exists)
{
winRate = (float)(double)entry.Child("winRate").Value;
}
else
{
winRate = 0;
}
LeaderBoard.ListUp(nickname,win,winRate);
Debug.Log($"{LeaderBoard.ranker[index].nickName}{LeaderBoard.ranker[index].win}"); // 이건 실행 안됨
index++;
}
});
}
챗지피티, 강사님, 같은 수강 동료들 등 이유를 물어물어봤으나 답이 안나왔는데, 이전에 공부하면서 작성한 코드를 보니 정답이보였다.
FirebaseDatabase db
void Awake()
{
db = FirebaseDatabase.DefaultInstance;
db.GoOnline();
}
파이어베이스의 Realtime Database를 쓸 때는 GoOnline을 해줘야 한다.
플레이어의 정보를 저장할 때는 UserData 클래스 객체를 Json으로 저장하고, 불러올 때도 Json으로 불러온 다음, UserData로 변환해서 사용한다.
유저들의 정보를 클래스 객체로 저장한다
[System.Serializable]
public class UserData
{
public string userName;
public int wins;
public int losses;
public float winRate;
public UserData(string userName, int wins, int losses, float winRate)
{
this.userName = userName;
this.wins = wins;
this.losses = losses;
this.winRate = winRate;
}
}
리더보드에 등록되는 유저의 정보를 담는 클래스다.
[System.Serializable]
public class LeaderBoardEntry
{
public string nickName;
public int win;
public float winRate;
public LeaderBoardEntry(string nickName, int win, float winRate)
{
this.nickName = nickName;
this.win = win;
this.winRate = winRate;
}
}
LeaderBoardEntry를 리스트로 가지고 있다. 리더보드에서 1위부터 10위까지 걸리게 되는 유저 데이터를 가진다.
public class LeaderBoard : MonoBehaviour
{
[SerializeField] public List<LeaderBoardEntry> ranker = new List<LeaderBoardEntry>();
[SerializeField] public List<UserData> userData = new List<UserData>();
public void SetLeaderBoard()
{
Manager.FB.GetLeaderBoard();
}
public void UserDataToLeaderBoard(List<UserData> userData)
{
ranker.Clear();
this.userData = userData;
userData.Sort((a, b) => b.wins.CompareTo(a.wins));
for (int i = 0; i < 10; i++)
{
ListUp(userData[i].userName,userData[i].wins,userData[i].winRate);
}
}
private void ListUp(string nickName, int win, float winRate)
{
LeaderBoardEntry entry = new LeaderBoardEntry(nickName,win,winRate);
ranker.Add(entry);
}
}
리스트를 한 번 내림차 순으로 정렬해서 순서대로 Leaderboard의 리스트에 집어넣는다. 그러면 순서대로 1위 ~ 10위가 된다.
파이어 베이스에 UserData 클래스 객체를 json으로 변환한 후 현재 유저의 uid 하위로 저장한다.
public void TestSave()
{
UserData userData = new(testName, testWin, testLose, testWinRate);
string json = JsonUtility.ToJson(userData);
userRef.SetRawJsonValueAsync(json).ContinueWithOnMainThread(task => {
if (task.IsCompleted)
{
Debug.Log("닉네임 업로드 성공");
}
else
{
Debug.LogError("닉네임 업로드 실패: " + task.Exception);
}
});
}
파이어베이스에서 현재 유저의 uid를 기준으로 json으로 데이터를 불러오고, UserData 클래스 객체로 변환한다.
public void GetLeaderBoard()
{
user = Auth.CurrentUser;
uid = user.UserId;
userRef = dbRef.Child("users").Child(uid); // 사용자 데이터 경로 지정
List<UserData> userDatas = new List<UserData>(); // 결과를 저장할 리스트
Debug.Log("여기는 들어옴"); //여기 들어오는것 확인 됨 dbRef.Child("users").OrderByChild("wins").LimitToLast(10).GetValueAsync().ContinueWithOnMainThread(task =>
{
if (task.IsCanceled)
{
Debug.LogWarning("리더보드 불러오기 취소");
}
if (task.IsFaulted)
{
Debug.LogWarning($"리더보드 불러오기 실패{task.Exception?.InnerException?.Message}");
}
DataSnapshot snapshot = task.Result;
foreach (var entry in snapshot.Children)
{
string json = entry.GetRawJsonValue();
UserData fromJson = JsonUtility.FromJson<UserData>(json);
userDatas.Add(fromJson);
}
LeaderBoard.GetUserData(userDatas); //리더보드 객체에 결과 전달
});
}

저장된 값이 순서대로 잘 불러와진다.