[Unity] PlayerPrefs를 이용한 랭킹시스템

네,가능합니다 ㅣ 2024. 10. 20. 17:10

이틀전에인가.. 저녁에 만들었던 코드이다.

인터넷에서 찾아보며 만들고 나니 나중에 봤을때 코드의 흐름이 잘 이해가 되지 않았다.

자기가 작성한 코드를 봤을때 이해가 되지 않는건 부끄러우니까 코드 리뷰를 하긴 해야겠다 했는데

일요일인 오늘 시간이 나서 해보기로 했다.

 

[System.Serializable]
public class RankEntry
{
    public string playerName;
    public int score;

    public RankEntry(string playerName, int score)
    {
        this.playerName = playerName;
        this.score = score;
    }
}

 

위 코드는 간단하게 설명하자면 데이터를 직렬화 해서 저장하기 위한 틀이다.

 

여기서 "직렬화"란 ? 객체의 상태를 저장 혹은 전송 하기위해 객체를 변환하는 과정이다.

데이터를 저장할 때 객체의 상태를 파일에 기록 하기 위한 과정이라고 생각하면 된다.

반대로 이 기록된 데이터를 객체로 변환하는것은 역 직렬화이다.

 

그리고 아래에서 보여줄 코드는 사실 PlayerPrefs를 사용하며, 복잡하지 않은 String값과 Int값만 저장하기에 위의 직렬화 코드는 굳이 필요하지 않았다.

 

하지만 앞으로의 과정에 이런 습관은 도움이 될 것 같아 작성하게 된 코드이다.

 

아래의 코드는 실질적으로 랭킹시스템을 관리하는 코드이다.

 

설명은 코드를 보며 주석에 작성하도록 하겠다

 

using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class RankingManager : MonoBehaviour
{
    private const int maxRankCount = 5;

    public TMP_Text[] nameTexts;
    public TMP_Text[] scoreTexts;

    // rankList 에 RankEntry형식의 객체를 담을 수 있는 리스트를 생성
    private List<RankEntry> rankList = new List<RankEntry>();

    private void Start()
    {
        LoadRanking();
        UpdateRankingUI();
    }

    public void AddNewScore(string playerName, int score)
    {
        // RankEntry 클래스를 사용하여 매개변수로 받아온 이름과 점수를 newEntry에 RankEntry형식으로 담아주고 객체화 하고
        RankEntry newEntry = new RankEntry(playerName, score);
        rankList.Add(newEntry);  // rankList 리스트에 newEntry 객체를 추가

        // 점수를 기준으로 내림차순으로 정렬(람다식) 간단하게 "리스트명.Sort((entry1, entry2) => entry2.비교할변수.CompareTo(entry1.score));"
        // 자세하게 설명하면 entry2.비교할변수.CompareTo(entry1.비교할변수) 에서 entry2가 entry1보다 크면 양수 같으면 0, 적으면 음수를 반환한다.
        rankList.Sort((entry1, entry2) => entry2.score.CompareTo(entry1.score));

        // 점수가 적든 많든 추가했으니 가장 낮은 점수를 1개 제거해야함 맥스랭킹이 5니까 6개라면 if문 작동
        if (rankList.Count > maxRankCount)
        {
            // 리스트가6개라면 0 1 2 3 4 5 이렇게 저장되어있을거고 위에서 내림차순 정렬했으니 5번을 삭제해야함 그러면 count는 6이니까 -1 해서 5번 RemoveAt으로 5번을 삭제
            rankList.RemoveAt(rankList.Count - 1);
        }

        SaveRanking();
        UpdateRankingUI();
    }

    private void SaveRanking()
    {
        // 데이터 저장하기 (이부분이 이해가 안되면 PlayerPrefs 및 List에 관한 설명을 찾아볼것.)
        for (int i = 0; i < rankList.Count; i++)
        {
            PlayerPrefs.SetString($"RankName{i}", rankList[i].playerName);
            PlayerPrefs.SetInt($"RankScore{i}", rankList[i].score);
        }
        PlayerPrefs.Save();
    }

    private void LoadRanking()
    {
        rankList.Clear();

        // 저장된 데이터 불러오기 (이부분이 이해가 안되면 PlayerPrefs에 관한 설명을 찾아볼것.)
        for (int i = 0; i < maxRankCount; i++)
        {
            if (PlayerPrefs.HasKey($"RankName{i}") && PlayerPrefs.HasKey($"RankScore{i}"))
            {
                string playerName = PlayerPrefs.GetString($"RankName{i}");
                int score = PlayerPrefs.GetInt($"RankScore{i}");
                rankList.Add(new RankEntry(playerName, score));
            }
        }
    }

    private void UpdateRankingUI()
    {
        for (int i = 0; i < maxRankCount; i++)
        {
            if (i < rankList.Count)
            {
                nameTexts[i].text = rankList[i].playerName;
                scoreTexts[i].text = rankList[i].score.ToString();
            }
            else
            {
                // (예외처리) 저장된 데이터가 모자라면 표시
                nameTexts[i].text = "---";
                scoreTexts[i].text = "---";
            }
        }
    }
}

 

끗 (사실 작성하고 이해하고나면 어렵지 않은 코드들이다. 생각만으로는 오 구현하기 꽤 어렵겠는데,, 싶은 로직들도

뜯어보고나면 다 알고있는 방법들이다. 정말 대부분의 코드가 그렇다 .. 뭐 수학식이 많이 들어간 코드들 제외하고...

)