본문 바로가기
프로그래밍/유니티

[Unity C#] PlayerPrefs로 기기에 저장되는 랭킹 만들기

by 김시루시루르 2021. 12. 3.

학교다닐때 과제로 냈던 유니티 프로젝트에 썼던 코드

얼렁뚱땅 PalyerPrefs로만 구현했습니다. 오직! 플레이어프립스로만!

 

플레이어프립스 특징 상, 기기에 저장되는 랭킹입니다.

그때 이걸 만들면서 이거 제법 한계인 기능이군.. 이라고 생각했는데

익명의 피드백(다른 팀 피드백까지가 과제였으므로)에서

"랭킹이 기기에만 저장된다는게 좋아요~" 라는 평가를 보고 헤헤 그런가 (코슥) 했던 기억이

하긴 저도 제 점수가 공공연하게 서버 판에 올라가는걸 별로 좋아하지 않긴 합니다.

그분도 이런 맥락이었겠지 아마


1. 랭킹 창 구조

여기서 랭킹은, 게임오버 후 플레이어가 이름을 입력하면 랭킹 계산을 한 뒤 보여주도록 했습니다.

 

이름과 점수 각각의 텍스트 박스로 구성되어 있고, 지금까지의 1~5위와 나의 점수를 보여줍니다.

나의 점수가 랭킹 안에 들어있다면, 1~5위 안에 나의 점수가 포함되어 나타납니다.

또 오른쪽 이미지처럼, 내 점수가 랭킹 안에 들어갔다면 그걸 색깔을 통해 강조표시를 해줍니다.


2. 랭킹을 정렬하는 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
private float[] bestScore = new float[5];
private string[] bestName = new string[5];
 
//현재 플레이어의 점수와 이름을 받아서 실행
void ScoreSet(float currentScore, string currentName)
{
    //일단 현재에 저장하고 시작
    PlayerPrefs.SetString("CurrentPlayerName", currentName);
    PlayerPrefs.SetFloat("CurrentPlayerScore", currentScore));
 
    float tmpScore = 0f;
    string tmpName = "";
 
    for (int i = 0; i < 5; i++)
    {
        //저장된 최고점수와 이름을 가져오기
        bestScore[i] = PlayerPrefs.GetFloat(i + "BestScore");
        bestName[i] = PlayerPrefs.GetString(i + "BestName");
 
        //현재 점수가 랭킹에 오를 수 있을 때
        while (bestScore[i] < currentScore)
        {
            //자리바꾸기!
            tmpScore = bestScore[i];
            tmpName = bestName[i];
            bestScore[i] = currentScore;
            bestName[i] = currentName;
 
            //랭킹에 저장
            PlayerPrefs.SetFloat(i + "BestScore", currentScore);
            PlayerPrefs.SetString(i.ToString() + "BestName", currentName);
 
            //다음 반복을 위한 준비
            currentScore = tmpScore;
            currentName = tmpName;
        }
    }
    //랭킹에 맞춰 점수와 이름 저장
    for (int i = 0; i < 5; i++)
    {
        PlayerPrefs.SetFloat(i + "BestScore", bestScore[i]);
        PlayerPrefs.SetString(i.ToString() + "BestName", bestName[i]);
    }
}
cs

이 코드를 시작하기 전에, 먼저 현재 플레이어의 이름과 점수를 PlayerPrefs를 통해 저장해줍니다.

이름은 String으로 CurrentPlayerName, 점수는 Float으로 CurrentPlayerScore에 저장했습니다.

 

이건 결과창에서 현재 나의 이름과 점수를 보여주기 위한 목적으로,

다른 참조 방식을 사용하신다면 굳이 플레이어 프리펩에 저장하실 필요는 없습니다.

 

1차원 배열을 선언하고, 그 배열을 내림차순으로 정리해서 PlayerPrefs에 넣어주는 코드입니다.

Array.Sort등을 써도 좋겠지만.. 그때는? 몰랐으므로?

게다가 이름까지 같이 정렬해줘야 한다는 사실이 또 그렇군요

여튼 자리를 바꿔줍니다.

 

1위부터 5위까지가 10 8 7 6 5 점이고, 현재 플레이어가 9점이라고 생각해보면

현재 플레이어는 2위가 되고, 기존 5위 플레이어는 랭킹 밖으로 나가야 하는데요

21번의 while 조건에서 10 < 9는 참이 아니므로 자리바꾸기는 일어나지 않습니다.

그리고 그 외의 8 < 9 등에서는 참이므로 자리바꾸기가 일어나는거죠

 

8 < 9의 실행을 다시 예로 들자면

임시 변수에 8을 넣고, 8이 빠진 자리에 9를 넣고, 8이 있던 자리 (랭킹 배열[1])에

9라는 점수를 넣어주는 것으로 9의 점수와 이름이 랭킹에 들어갈 수 있습니다.

그리고 8은 다음 비교 대상이 되어 다음 while문에선 7 < 9가 아니라 7 < 8이 됩니다.

이렇게 총 5번을 for문을 통해 반복하기 때문에, 자연스럽게 기존 5위 값은 사라지게 됩니다.

 

이후 완성된 랭킹 정보를 플레이어 프립스에 저장합니다.

이제 불러오기만 하면 됩니다.


3. 랭킹을 보여주는 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//플레이어 이름, 점수 텍스트를 현재 '나'의 이름과 점수에 표시
RankNameCurrent.text = PlayerPrefs.GetString("CurrentPlayerName");
RankScoreCurrent.text =
    string.Format("{0:N3}cm"PlayerPrefs.GetFloat("CurrentPlayerScore"));
 
//랭킹에 맞춰 불러온 점수와 이름을 표시하는 부분
for (int i = 0; i < 5; i++)
{
    rankScore[i] = PlayerPrefs.GetFloat(i + "BestScore");
    RankScoreText[i].text = string.Format("{0:N3}cm", rankScore[i]);
    rankName[i] = PlayerPrefs.GetString(i.ToString() + "BestName");
    RankNameText[i].text = string.Format(rankName[i]);
 
    //강조 표시
    if (RankScoreCurrent.text == RankScoreText[i].text)
    {
        Color Rank = new Color(2552250);
        RankText[i].color = Rank;
        RankNameText[i].color = Rank;
        RankScoreText[i].color = Rank;
    }
}
cs

글을 거의 다 쓰고보니 굳이 PlayerPrefs일 필요는 없는것같네요 (머쓱)...

요는 현재 플레이어의 이름과 점수, 저장된 랭킹 정보를 가져온다입니다.

저는 서로 다른 스크립트 파일에서 이걸 실행하고 있어서 대충 플레이어프립스로 했을 뿐 (?)

 

우선 UI에 표시하기 위해, 현재 나의 이름과 점수를 보여주는 텍스트에 값을 넣습니다. (1~4번줄)

RankNameCurrent = 현재 나의 이름을 보여주는 텍스트

RankScoreCurrent = 현재 나의 점수를 보여주는 텍스트

점수는 소수점 세 자리까지 보여주고 싶어서 {N3}을 했어요!

 

그리고 UI에 다른 랭킹을 표시해줘야 하겠죠.

이 위쪽에서 RankScoreText와 RankNameText의 배열을 만들어서 텍스트UI를 여기에 참조해줬습니다.

이제 이 참조해준 UI 텍스트의 값을 랭킹 텍스트로 변경합니다.

 

강조 표시는 랭킹에 오른 점수 텍스트와 현재의 점수 텍스트 값이 같을 경우를 조건으로 걸었는데,

이 경우 자신과 똑같은 점수를 가진 사람도.. 강조 표시 될 것 같네요.

이때는 약간 이걸 막기 위해서 표시를 소수점 3자리까지 한 건데. 지금 보니 완벽하지 않군.

이러면 뭐 소수점을 잘라내기 전의 값으로 비교를 하면 될 일입니다...

 

+ 소수점 세자리까지의 점수가 동일할 때의 중복 강조를 막기

1
2
3
4
5
6
7
8
//강조 표시
if (PlayerPrefs.GetFloat("CurrentPlayerScore"== rankScore[i])
{
    Color Rank = new Color(2552250);
    RankText[i].color = Rank;
    RankNameText[i].color = Rank;
    RankScoreText[i].color = Rank;
}
cs

그래서 썼다.

 

참고로 RankText는 순위를 보여주는 텍스트입니다.

이것도 마찬가지로 배열을 만들어서 텍스트 UI를 참조시켜줬습니다.

댓글