2026-07-14 11:14:13 +03:00

203 lines
6.3 KiB
C#

using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class Leaderboard : MonoBehaviour
{
GameManager gm;
[SerializeField] Transform headerRow;
[SerializeField] List<Transform> Rows;
[SerializeField] Transform rankedRow;
[SerializeField] Transform rankedPanel;
[SerializeField] GameObject instruction;
[SerializeField] Vector2 specialPanelLocal, rankedPanelLocal, rankedPanelLocalOnly;
[SerializeField] GameObject tgQr, whatsQr;
[Header("Маркировка бот/игрок")]
[SerializeField] List<Color> playerColors;
[SerializeField] List<Color> botColors;
List<PlayerStatsRecord> topRecords;
[SerializeField] GameObject RowPrefab;
[SerializeField] GameObject RowPrefabRanked;
[SerializeField] int MaxRows = 100;
[SerializeField] Transform RowsRoot;
[SerializeField] Vector2 RowOffset = new Vector2(0, -90);
[SerializeField] Vector2 startAnchoredPosition = new Vector2(0, 45);
public float accelerationY = 5;
public float speedY = 0;
public float maxSpeedY = 300;
Coroutine slideCoroutine;
private string dateFormat = "dd.MM.yy HH:mm";
private void OnDisable()
{
foreach (var row in Rows)
{
Destroy(row.gameObject);
}
Rows.Clear();
if (slideCoroutine != null)
StopCoroutine(slideCoroutine);
}
public void Initialize()
{
gm = GameManager.instance;
rankedPanel.localPosition = rankedPanelLocalOnly;
instruction.SetActive(true);
int totalRecords = gm.StatsService.GetTotalRecordsCount();
int total = Mathf.Min(MaxRows, totalRecords);
topRecords = gm.StatsService.GetTopPlayers(total);
//тут надо спавить Ряды
SpawnRows(total);
ClearRowsText();
for (int i = 0; i < total; i++)
{
FillRow(i, topRecords[i]);
}
FillRow(rankedRow, gm.StatsService.GetLatestRecord());
rankedRow.gameObject.SetActive(true);
slideCoroutine = StartCoroutine(SlideCoroutine());
speedY = 0;
}
IEnumerator SlideCoroutine()
{//надо еще максимальный слайд рассчитать
float minY = startAnchoredPosition.y;
float maxY = startAnchoredPosition.y - RowOffset.y *Rows.Count + (RowOffset.y*3);
float calculatedOffsetY = minY;
List<RectTransform> cachedRects = new List<RectTransform>();
foreach (Transform row in Rows)
{
cachedRects.Add(row.GetComponent<RectTransform>());
}
while (true)
{
speedY += accelerationY * Time.deltaTime;
speedY = Mathf.Clamp(speedY, -maxSpeedY, maxSpeedY);
calculatedOffsetY += speedY*Time.deltaTime;
calculatedOffsetY = Mathf.Clamp(calculatedOffsetY, minY, maxY);
//применить циклом смещение ко всем рядам
for (int i = 0; i < Rows.Count; i++)
{
cachedRects[i].anchoredPosition = startAnchoredPosition + RowOffset * i + Vector2.up * calculatedOffsetY;
}
yield return null;
}
}
void SpawnRows(int amount)
{
Rows = new List<Transform>();
int latestRecordIndex = gm.StatsService.GetRecordRank(gm.StatsService.GetLatestRecord()) - 1;
for (int i = 0; i < amount; i++)
{
GameObject prefab = i == latestRecordIndex ? RowPrefabRanked : RowPrefab;
GameObject go = Instantiate(prefab, RowsRoot);
RectTransform rect = go.GetComponent<RectTransform>();
rect.anchoredPosition = startAnchoredPosition + RowOffset * i;
Rows.Add(rect);
}
}
public void ClearRowsText()
{
for (int i = 0; i < Rows.Count; i++)
{
for (int j = 0; j < 5; j++)
{
Rows[i].GetChild(j).GetComponentInChildren<TextMeshProUGUI>().text = "—";
}
}
for (int j = 0; j < 5; j++)
{
rankedRow.GetChild(j).GetComponentInChildren<TextMeshProUGUI>().text = "—";
}
}
private void FillRow(int rowIndex, PlayerStatsRecord record)
{
Transform row = Rows[rowIndex];
row.GetChild(0).GetComponentInChildren<TextMeshProUGUI>().text = (rowIndex + 1).ToString();
row.GetChild(1).GetComponentInChildren<TextMeshProUGUI>().text = GetMarkedName(record.PlayerName, record.IsBot);
row.GetChild(2).GetComponentInChildren<TextMeshProUGUI>().text = secondsToMinutes((int)record.CompletionTimeSec);
row.GetChild(3).GetComponentInChildren<TextMeshProUGUI>().text = record.MovesCount.ToString();
row.GetChild(4).GetComponentInChildren<TextMeshProUGUI>().text = record.CompletedAt.ToString(dateFormat);
}
private void FillRow(Transform row, PlayerStatsRecord record)
{
int rank = gm.StatsService.GetRecordRank(record);
row.GetChild(0).GetComponentInChildren<TextMeshProUGUI>().text = rank.ToString();
row.GetChild(1).GetComponentInChildren<TextMeshProUGUI>().text = GetMarkedName(record.PlayerName, record.IsBot);
row.GetChild(2).GetComponentInChildren<TextMeshProUGUI>().text = secondsToMinutes((int)record.CompletionTimeSec);
row.GetChild(3).GetComponentInChildren<TextMeshProUGUI>().text = record.MovesCount.ToString();
row.GetChild(4).GetComponentInChildren<TextMeshProUGUI>().text = record.CompletedAt.ToString(dateFormat);
}
public void DisplayCurrentPlayer(PlayerStatsRecord record)
{
rankedRow.gameObject.SetActive(true);
FillRow(rankedRow, record);
}
string secondsToMinutes(int seconds)
{
int minutes = seconds / 60;
int remainingSeconds = seconds % 60;
return $"{minutes:D2}:{remainingSeconds:D2}";
}
//маркируем цветами ботовские рекорды и рекорды игрока.
string GetMarkedName(string name, bool isBot)
{
List<Color> colors = isBot ? botColors : playerColors;
if (colors == null || colors.Count == 0) return name;
int rand = Random.Range(0, colors.Count);
string hex = ColorUtility.ToHtmlStringRGB(colors[rand]);
return $"{name}<color=#{hex}>*</color>";
}
}