VanguardReMaster/client/Assets/Vanguard/Runtime/UI/PlayerTopBar.cs

294 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using UnityEngine;
using UnityEngine.UI;
using Vanguard.App;
using Vanguard.State;
namespace Vanguard.UI
{
/// <summary>
/// Верхняя панель игрока, общая для Lobby и DeckBuilder: аватар-инициалы,
/// ник, MMR, сезон, Rating/Community и гамбургер-меню.
/// </summary>
public sealed class PlayerTopBar : IDisposable
{
public const string RootName = "PlayerTopBar";
private const float Margin = 24f;
private const float Height = 96f;
private static readonly Color Border = new Color(0.18f, 0.49f, 1f, 0.55f);
private static readonly Color BorderStrong = new Color(0.34f, 0.72f, 1f, 0.9f);
private static readonly Color TextPrimary = new Color(0.88f, 0.93f, 1f);
private static readonly Color TextMuted = new Color(0.58f, 0.69f, 0.88f);
private static readonly Color TextDim = new Color(0.44f, 0.55f, 0.75f);
private static readonly Color Accent = new Color(0.37f, 0.69f, 1f);
private readonly PlayerState _player;
private readonly HamburgerMenu _menu;
private readonly RectTransform _root;
private Text _avatar;
private Text _playerName;
private Text _mmr;
private bool _disposed;
public PlayerTopBar(
Transform parent,
AppConfig config,
PlayerState player,
Action onLoggedOut,
Action onHistory,
Action onRating,
Action onCommunity,
Action onLobby = null,
Transform overlayParent = null)
{
_player = player;
var top = Surface(parent, RootName, new Color(0.012f, 0.03f, 0.08f, 0.94f), 0);
_root = top;
top.anchorMin = new Vector2(0f, 1f);
top.anchorMax = new Vector2(1f, 1f);
top.pivot = new Vector2(0.5f, 1f);
top.offsetMin = new Vector2(Margin, -Height);
top.offsetMax = new Vector2(-Margin, 0f);
var avatarRect = Surface(
top,
"Avatar",
new Color(0.05f, 0.13f, 0.3f, 0.95f),
14);
avatarRect.anchorMin = new Vector2(0f, 0.5f);
avatarRect.anchorMax = new Vector2(0f, 0.5f);
avatarRect.pivot = new Vector2(0f, 0.5f);
avatarRect.sizeDelta = new Vector2(64f, 64f);
avatarRect.anchoredPosition = new Vector2(20f, 0f);
_avatar = UiKit.CreateText(avatarRect, "Initials", "?", 26, TextPrimary);
_avatar.fontStyle = FontStyle.Bold;
UiKit.Stretch(_avatar.rectTransform);
UiKit.MakeLiteral(_avatar);
_playerName = UiKit.CreateText(
top,
"PlayerName",
"…",
22,
TextPrimary,
TextAnchor.MiddleLeft);
_playerName.fontStyle = FontStyle.Bold;
var nameRect = _playerName.rectTransform;
nameRect.anchorMin = new Vector2(0f, 0.5f);
nameRect.anchorMax = new Vector2(0f, 0.5f);
nameRect.pivot = new Vector2(0f, 0.5f);
nameRect.sizeDelta = new Vector2(420f, 30f);
nameRect.anchoredPosition = new Vector2(104f, 14f);
UiKit.MakeLiteral(_playerName);
_mmr = UiKit.CreateText(
top,
"Mmr",
string.Empty,
14,
TextMuted,
TextAnchor.MiddleLeft);
var mmrRect = _mmr.rectTransform;
mmrRect.anchorMin = new Vector2(0f, 0.5f);
mmrRect.anchorMax = new Vector2(0f, 0.5f);
mmrRect.pivot = new Vector2(0f, 0.5f);
mmrRect.sizeDelta = new Vector2(460f, 22f);
mmrRect.anchoredPosition = new Vector2(104f, -16f);
UiKit.MakeLiteral(_mmr);
var season = UiKit.CreateText(
top,
"Season",
"Сезон — скоро",
14,
TextDim,
TextAnchor.MiddleCenter);
var seasonRect = season.rectTransform;
seasonRect.anchorMin = new Vector2(0.5f, 0.5f);
seasonRect.anchorMax = new Vector2(0.5f, 0.5f);
seasonRect.sizeDelta = new Vector2(280f, 30f);
seasonRect.anchoredPosition = Vector2.zero;
AddAction(top, "Rating", "Рейтинг", -312f, 180f, onRating, LobbyIcon.Chart);
AddAction(top, "Community", "Сообщество", -96f, 200f, onCommunity, LobbyIcon.Friends);
if (onLobby != null)
AddAction(top, "ToLobby", "← В лобби", -508f, 160f, onLobby, null);
_menu = new HamburgerMenu(
top,
config,
onLoggedOut,
onHistory,
onLobby,
"Меню",
overlayParent);
_player.Changed += UpdateTexts;
Loc.LanguageChanged += UpdateTexts;
UpdateTexts();
}
public bool IsMenuOpen => _menu != null && _menu.IsOpen;
public RectTransform Root => _root;
public void CloseMenu()
{
if (_menu != null)
_menu.Close();
}
public void Dispose()
{
if (_disposed)
return;
_disposed = true;
_player.Changed -= UpdateTexts;
Loc.LanguageChanged -= UpdateTexts;
}
private void UpdateTexts()
{
if (_disposed)
return;
var name = string.IsNullOrEmpty(_player.UserName) ? "…" : _player.UserName;
_playerName.text = name;
_avatar.text = Initial(name);
_mmr.text = "MMR " + _player.RankedMmr
+ " · " + Loc.Translate("матчей") + " " + _player.Matches
+ " · " + Loc.Translate("побед") + " " + WinsPercent();
}
private string WinsPercent()
{
if (_player.Matches <= 0)
return "0%";
return Mathf.RoundToInt(_player.Wins * 100f / _player.Matches) + "%";
}
private static string Initial(string name)
{
foreach (var character in name)
{
if (char.IsLetterOrDigit(character))
return char.ToUpperInvariant(character).ToString();
}
return "?";
}
private static void AddAction(
RectTransform parent,
string name,
string label,
float rightOffset,
float width,
Action onClick,
Action<RectTransform, Color> icon)
{
var buttonRect = Surface(parent, name, new Color(0.035f, 0.09f, 0.21f, 0.85f), 12);
buttonRect.anchorMin = new Vector2(1f, 0.5f);
buttonRect.anchorMax = new Vector2(1f, 0.5f);
buttonRect.pivot = new Vector2(1f, 0.5f);
buttonRect.sizeDelta = new Vector2(width, 52f);
buttonRect.anchoredPosition = new Vector2(rightOffset, 0f);
var image = buttonRect.GetComponent<Image>();
image.raycastTarget = true;
var button = buttonRect.gameObject.AddComponent<Button>();
button.targetGraphic = image;
button.transition = Selectable.Transition.ColorTint;
button.colors = HoverColors();
if (onClick != null)
button.onClick.AddListener(() => onClick());
else
button.interactable = false;
var textLeft = 18f;
if (icon != null)
{
var iconColor = onClick != null
? Accent
: new Color(Accent.r, Accent.g, Accent.b, 0.35f);
var iconRect = Icon(buttonRect, new Vector2(30f, 30f), new Vector2(-width * 0.5f + 30f, 0f), 0.6f);
icon(iconRect, iconColor);
textLeft = 52f;
}
var text = UiKit.CreateText(
buttonRect,
"Label",
label,
17,
onClick != null ? TextPrimary : new Color(TextPrimary.r, TextPrimary.g, TextPrimary.b, 0.4f),
TextAnchor.MiddleLeft);
var textRect = text.rectTransform;
textRect.anchorMin = new Vector2(0f, 0f);
textRect.anchorMax = new Vector2(1f, 1f);
textRect.offsetMin = new Vector2(textLeft, 0f);
textRect.offsetMax = new Vector2(-14f, 0f);
}
private static RectTransform Surface(
Transform parent,
string name,
Color fill,
int radius)
{
var go = new GameObject(name, typeof(RectTransform), typeof(Image));
var rect = (RectTransform)go.transform;
rect.SetParent(parent, false);
var image = go.GetComponent<Image>();
image.sprite = NeonUi.BodySliced(
radius,
fill,
radius > 0 ? Border : new Color(Border.r, Border.g, Border.b, 0.35f),
1);
image.type = Image.Type.Sliced;
image.color = Color.white;
image.raycastTarget = false;
return rect;
}
private static RectTransform Icon(
Transform parent,
Vector2 size,
Vector2 position,
float scale)
{
var go = new GameObject("Icon", typeof(RectTransform));
var rect = (RectTransform)go.transform;
rect.SetParent(parent, false);
rect.anchorMin = new Vector2(0.5f, 0.5f);
rect.anchorMax = new Vector2(0.5f, 0.5f);
rect.pivot = new Vector2(0.5f, 0.5f);
rect.sizeDelta = size;
rect.anchoredPosition = position;
rect.localScale = Vector3.one * scale;
return rect;
}
private static ColorBlock HoverColors()
{
return new ColorBlock
{
normalColor = Color.white,
highlightedColor = new Color(1.16f, 1.16f, 1.16f, 1f),
pressedColor = new Color(0.9f, 0.9f, 0.9f, 1f),
selectedColor = Color.white,
disabledColor = new Color(0.55f, 0.55f, 0.55f, 0.6f),
colorMultiplier = 1f,
fadeDuration = 0.08f,
};
}
}
}