본문 바로가기
App && Game

[유니티 / Unity] 랭킹 보드 UI 및 기능 만들기

by 배애앰이 좋아 2025. 3. 15.
반응형

 

안녕하세요!

오랜만에 게임을 만들다가 랭킹 보드를 만들어야 했는데 옛날에 만들었던 걸 재활용하려고 보니깐 없어서 다시 노가다하지 않도록 이렇게 글을 적게 되었습니다. 랭킹보드는 멀티 게임에 주로 이용되기도 하고 혼자 챌린지할 때도 기록할 경우에 활용되는 것 같습니다.

 



먼저, 제가 만든 최종 견본 보여드립니다.
물론 제가 간이로 만든 거라 각자 원하시는 데로 항목들은 수정하시면 됩니다. 

커다란 이미지 보드 위에 타이틀바, 내용바, 자신의 기록바를 만들었습니다.
저는 디자이너가 아니다 보니 그냥 간단한 사각형을 이용하여 다음과 같이 구현하였습니다.
사실 제일 좋은 거는 Unity Asset 에서 제공하는 무료 랭킹 패키지 받으시면 디자인도 되어 있어 좋지만 버전 문제나 오히려 복잡해서 귀찮을 거 같으면 저처럼 만드시면 될 것 같습니다.

 

RankBoardUI.unitypackage
0.01MB



깔끔하게 만드는 팁은 Vertical Layout Group 과 Content Size Filter 를 이용하시면 자동으로 정렬해주어서 매우 편합니다. 일단, 먼저 prefab asset 올려드립니다. 위에 보이는 canvas 가 올라가 있습니다.

 


두 가지가 있는데 첫 번째로는 위에 사진에서 전체를 구상하는 화면과

 


두 번째로는 각 유저들의 정보들이 들어갈 정보바로 나눠서 구현하시면 깔끔하고 추가하기 좋습니다.

 


먼저 전체 화면에서 유저들의 정보들이 쭉 들어가는 Content를 위에와 같이 설정해주었습니다.

 


그 다음으로는 이 화면에 RankManager.cs 를 붙여서 전반적인 관리해줍니다.

 

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[Serializable]
public class PlayerRank
{
    public string playerName;
    public string birthNum;
    public int score;
    public PlayerRank(string playerName, string birthNum, int score)
    {
        this.playerName = playerName;
        this.birthNum = birthNum;
        this.score = score;
    }
}

public class RankManager : MonoBehaviour
{
    [SerializeField] private GameObject rankBoard;
    [SerializeField] private GameObject rankBarPrefab;
    [SerializeField] private Transform rankListContainer;
    private List<PlayerRank> rankListInfo = new List<PlayerRank>();
    private List<GameObject> rankBarGameObjects = new List<GameObject>();
    private List<RankUI> rankBarScripts = new List<RankUI>();
    private RCGameManager manager;
    [SerializeField] private RankUI myRankInfo;

    public void OnRankBoard(bool isActive){
        rankBoard?.SetActive(isActive);
    }

    public void ChangeMyRankInfo(string playerName, string birthNum, int score){
        playerName = playerName.Substring(0, playerName.Length - 6);
        birthNum = birthNum.Substring(birthNum.Length - 6);

        int index = rankListInfo.FindIndex(p => p.playerName == playerName && p.birthNum == birthNum);
        PlayerRank player = rankListInfo[index];
        if (player != null)
        {
            myRankInfo.SettingInfo(index + 1, player.playerName, player.birthNum, player.score);
        }else{
            Debug.LogWarning($"Player {playerName} not found in the rank list!");
        }
    }

    public void AddRankList(string playerName, string birthNum, int score)
    {
        playerName = playerName.Substring(0, playerName.Length - 6);
        birthNum = birthNum.Substring(birthNum.Length - 6);

        GameObject rankBar = Instantiate(rankBarPrefab, rankListContainer);
        rankBarGameObjects.Add(rankBar);

        RankUI rankUI = rankBar.GetComponent<RankUI>();
        rankUI.SettingInfo(1, playerName, birthNum, score);
        rankBarScripts.Add(rankUI);

        PlayerRank newPlayer = new PlayerRank(playerName, birthNum, score);
        rankListInfo.Add(newPlayer);
        SortRanks();
    }

    public void UpdateRank(string playerName, int newScore)
    {
        string birthNum = playerName.Substring(playerName.Length - 6);
        playerName = playerName.Substring(0, playerName.Length - 6);
        
        PlayerRank player = rankListInfo.Find(p => p.playerName == playerName && p.birthNum == birthNum);
        if (player != null)
        {
            player.score = newScore;
            SortRanks();
        }else{
            Debug.LogWarning($"Player {playerName} not found in the rank list!");
        }

        if(manager == null){
            manager = GameObject.Find("GameManager").GetComponent<RCGameManager>();
        }
        if(manager != null){
            // manager.RobotSay("TIME_OVER");
            // manager.SendToGame("TIME_OVER");
        }
    }

    public void InitializeRanks()
    {
        rankListInfo.Clear();
        rankBarGameObjects.Clear();
        rankBarScripts.Clear();
        foreach (Transform child in rankListContainer)
        {
            Destroy(child.gameObject);
        }
    }

    public void SortRanks()
    {
        rankListInfo.Sort((player1, player2) => player2.score.CompareTo(player1.score));
        for(int i=0; i<rankListInfo.Count; i++){
            if (i < rankBarScripts.Count)
            {
                PlayerRank playerRank = rankListInfo[i];
                rankBarScripts[i].SettingInfo(i + 1 , playerRank.playerName, playerRank.birthNum, playerRank.score);
            }
            else
            {
                Debug.LogWarning($"Rank script not found for rank {i}.");
            }
        }
    }

    public PlayerRank FindPlayerRankInfo(string playerName)
    {
        PlayerRank player = rankListInfo.Find(p => p.playerName == playerName);
        if (player == null)
        {
            throw new KeyNotFoundException($"Player {playerName} not found in the rank list!");
        }
        return player;
    }

    public PlayerRank FindCurrentNumRankInfo(int rankNum)
    {
        return rankListInfo[rankNum];
    }
}



위 코드에서 살펴보면 유저 리스트를 더해주는 AddRankList / 기존에 있는 유저 점수 업데이트 하는 UpdateRank / 전체 초기화해주는 InitializeRanks / 점수 비교해서 정렬하는 SortRanks / 플레이어 이름으로 정보 찾는 FindPlayerRankInfo / 번호로 정보 찾는 FindCurrentNumRankInfo 를 가볍게 구현해놓았고 
편의를 위해서 PlayerRank class를 만들어서 하나의 유저 정보를 이 클래스를 활용해 저장하고 활용하고 있습니다.

 


원래는 전 위처럼 따로 RankManager 게임 오브젝트를 만들고 이 스크립트를 붙여서 외부에다가 관리했는데 상황에 따라 달라질 것 같습니다.

 


그리고 하나의 유저 정보를 관리해주기 위한 스크립트로 RankUI.cs 를 제작했고 랭킹판 안에 편리하게 집어넣기 위해 제작했습니다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class RankUI : MonoBehaviour
{
    public Text sequenceText;
    public Text playerNameText;
    public Text birthNumText;
    public Text scoreText;

    public void SettingInfo(int sequence, string playerName, string birthNum, int score)
    {
        sequenceText.text = sequence.ToString();
        playerNameText.text = playerName;
        birthNumText.text = birthNum;
        scoreText.text = score.ToString();
    }
}



위의 스크립트는 간단하게 넣은 데이터에 따라 text 가 바뀌게 해서 데이터 관리보다는 보이는 걸 맡아주신다고 생각하면 될 것 같습니다.

여기까지가 아주 간단한 랭킹판 구현 실습이었습니다. 나중에 제가 또 노가다하지 않고 이 글을 참고하길 바라며 다른 분들도 유용하게 사용되길 바랍니다.


궁금한 점 있으면 댓글 달아주시길 바라며 글 읽어주셔서 감사합니다.

반응형

댓글