목차
※ 25.03.18(76일차)에는 예비군 작계 훈련으로 빠짐
오목 게임 만들기
25.03.19
Ranking Popup Panel 만들기
: 'Popup Panel'의 Prefab Variant로 생성
※ 급수에 따라 높은 급수가 더 위에 위치하도록 구현 (동일 급수인 경우 승률이 높은 유저가 위에 위치)
>> 'Panel'의 자식으로 'Scroll View' 생성
--> Anchor는 Alt + Shift
>> 'Content'에 'Content Size Fitter', 'Vertical Layout Group' 추가
>> Scrollbar Vertical
: Color는 Alpha 값을 0으로 설정
--> Scrollbar Horizontal은 삭제
>> Handle
>> Divider
--> Anchor는 Alt + Shift
└ 랭킹을 구현하기 위한 Cell 만들기
>> 'Panel'의 자식으로 'User Rank Cell' 생성
: UI-Image로 생성, User 정보는 가장 위에 배치하기 위해
※ Width는 'Content'의 자식으로 생성해서 위치를 조정했을 때 나온 수치
--> Anchor는 Alt + Shift
>> 'User Rank Cell'의 자식으로 'User Image', 'RankName Text', 'Victories Text' 생성
--> Anchor는 Alt + Shift
>> 만든 'User Rank Cell'을 'Content'의 자식으로 복붙 후, 이름을 'Rank Cell'으로 바꾸고 Prefab화
: 이후 Hierarchy에서 삭제
>> 코드 작성
- RankCellController.cs : RankCell의 내용을 넣어주는 Class
- RankingPanelController.cs : 'Content'의 자식으로 RankCell을 만들어주는 함수
--> 아직 서버가 구현되지 않았기 때문에 현재는 임시로 더미 유저 데이터를 만들어서 랭킹을 구현
>> 각각 맞게 함수 추가 및 바인딩
1. Ranking Popup Panel
2. Rank Cell
3. Main Panel
└ 구현된 모습
앞으로 개선 사항
※ UserData를 받아서 'User Rank Cell'에 대입
※ Panel이 중복으로 열리지 않도록 조치해야 한다.
※ Panel 외부를 클릭하면 Panel이 닫히도록 구현
최종 코드
>> MainPanelController.cs
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class MainPanelController : MonoBehaviour
{
[SerializeField] private Canvas canvas;
[SerializeField] private GameObject rankingPanelPrefab;
private ScoreInfo _playerScore = new ScoreInfo() // 임시 유저 정보
{
Nickname = "Test01",
WinCount = 8,
LoseCount = 2,
DrawCount = 0,
Rank = 17
};
private ScoreInfo[] _playerScores = new ScoreInfo[] // 임시 유저 더미 정보
{
new ScoreInfo { Nickname = "Test01", WinCount = 8, LoseCount = 2, DrawCount = 0, Rank = 17 },
new ScoreInfo { Nickname = "Test02", WinCount = 57, LoseCount = 32, DrawCount = 6, Rank = 9 },
new ScoreInfo { Nickname = "Test03", WinCount = 14, LoseCount = 23, DrawCount = 2, Rank = 13 },
new ScoreInfo { Nickname = "Test04", WinCount = 26, LoseCount = 16, DrawCount = 3, Rank = 13 },
};
/// <summary>
/// '대국 시작' 버튼을 눌렀을 때 호출되는 함수
/// </summary>
public void OnClickPlayButton()
{
GameManager.Instance.StartGame();
}
public void OnClickExitButton()
{
}
/// <summary>
/// '로그아웃' 버튼을 눌렀을 때 호출되는 함수
/// </summary>
public void OnClickLogoutButton()
{
}
#region Main Menu 버튼 클릭 함수
/// <summary>
/// '랭킹' 버튼을 눌렀을 때 호출되는 함수
/// </summary>
public void OnClickRankingButton()
{
if (canvas != null)
{
var rankingPanelObject = Instantiate(rankingPanelPrefab, canvas.transform);
var rankingPanelController = rankingPanelObject.GetComponent<RankingPanelController>();
//rankingPanelController.CreateRankCell(_playerScore);
rankingPanelController.CreateRankCells(_playerScores);
}
}
/// <summary>
/// '내 기보' 버튼을 눌렀을 때 호출되는 함수
/// </summary>
public void OnClickNotationButton()
{
}
/// <summary>
/// '상점' 버튼을 눌렀을 때 호출되는 함수
/// </summary>
public void OnClickShopButton()
{
}
/// <summary>
/// '설정' 버튼을 눌렀을 때 호출되는 함수
/// </summary>
public void OnClickSettingsButton()
{
}
#endregion
}
>> RankingPanelController.cs
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public struct ScoreInfo // 임시 코드
{
public string Nickname;
public int Rank;
public int WinCount;
public int LoseCount;
public int DrawCount;
}
[RequireComponent(typeof(PanelController))]
public class RankingPanelController : PanelController
{
[SerializeField] private GameObject rankCellPrefab;
[SerializeField] private Transform content;
/// <summary>
/// Content의 자식으로 Cell을 만들어주는 함수
/// </summary>
public void CreateRankCell(ScoreInfo scoreInfo)
{
var rankCellObject = Instantiate(rankCellPrefab, content);
var rankCellController = rankCellObject.GetComponent<RankCellController>();
rankCellController.SetCellInfo(scoreInfo);
}
/// <summary>
/// Content의 자식으로 Cell을 만들어주는 함수, 여러 임시 Player 더미를 만들어서 테스트하기 위함
/// </summary>
/// <param name="scoreInfos"></param>
public void CreateRankCells(ScoreInfo[] scoreInfos)
{
// Rank가 낮을수록 먼저 표시되도록 정렬하고 Rank가 같으면 승률이 높으면 먼저 표시되도록 정렬
var sortedScores = scoreInfos.OrderBy(player => player.Rank)
.ThenByDescending(player => rankCellPrefab.AddComponent<RankCellController>().GetWinRate(player))
.ToArray();
foreach (var scoreInfo in sortedScores)
{
var rankCellObject = Instantiate(rankCellPrefab, content);
var rankCellController = rankCellObject.GetComponent<RankCellController>();
rankCellController.SetCellInfo(scoreInfo);
}
}
}
>> RankCellController.cs
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class RankCellController : MonoBehaviour
{
[SerializeField] private Image userImage;
[SerializeField] private TMP_Text ranknameText;
[SerializeField] private TMP_Text victoriesText;
private int _totalCount;
/// <summary>
/// RankCell에 들어갈 정보를 서버로부터 받아서 넣어주는 함수
/// </summary>
public void SetCellInfo(ScoreInfo scoreInfo)
{
float winRateFloat = GetWinRate(scoreInfo);
int winRate = Mathf.RoundToInt(winRateFloat);
// TODO: 서버로부터 정보를 받아서 넣기
ranknameText.text = $"{scoreInfo.Rank}G {scoreInfo.Nickname}";
victoriesText.text =
$"{_totalCount}T {scoreInfo.WinCount}W {scoreInfo.LoseCount}L {scoreInfo.DrawCount}D ({winRate}%)";
}
/// <summary>
/// 승률을 구하는 함수
/// </summary>
/// <param name="scoreInfo">User의 데이터(임시 코드)</param>
/// <returns>float형식의 승률</returns>
public float GetWinRate(ScoreInfo scoreInfo)
{
_totalCount = scoreInfo.WinCount + scoreInfo.LoseCount + scoreInfo.DrawCount;
if (_totalCount == 0) return 0f;
return (scoreInfo.WinCount / (float)_totalCount) * 100;
}
}
'Development > Unity BootCamp' 카테고리의 다른 글
멋쟁이사자처럼부트캠프 Unity 게임 개발 3기 79, 80일차 (0) | 2025.03.21 |
---|---|
멋쟁이사자처럼부트캠프 Unity 게임 개발 3기 78일차 (0) | 2025.03.20 |
멋쟁이사자처럼부트캠프 Unity 게임 개발 3기 75일차 (0) | 2025.03.18 |
멋쟁이사자처럼부트캠프 Unity 게임 개발 3기 74일차 (0) | 2025.03.14 |
멋쟁이사자처럼부트캠프 Unity 게임 개발 3기 73일차 (0) | 2025.03.14 |