f31ffe910b
Netcode frontend pattern: UITK main menu / pause / settings (MenuUi + controllers), on-demand world lifecycle (WorldLauncher/SessionRunner), GameBootstrap menu branch; Graphics/Audio settings (SettingsService/GameVolume); single-slot save foundation (SaveData/SaveService, born-correct load at director spawn, autosave on Siege->Calm + quit); RuntimePanelSettings + theme; BuildTool menu; 10 EditMode tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
119 lines
4.8 KiB
C#
119 lines
4.8 KiB
C#
using System;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.InputSystem.UI;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace ProjectM.Client
|
|
{
|
|
/// <summary>
|
|
/// Shared UI Toolkit helpers for the code-built menu / settings / pause screens — a small palette + styled
|
|
/// element factories (so every screen reads in one visual language) plus runtime plumbing: loading the
|
|
/// shared <c>PanelSettings</c> (from Resources) and ensuring an <c>EventSystem</c> with an
|
|
/// <c>InputSystemUIInputModule</c> exists. Runtime UITK receives pointer/click events THROUGH the
|
|
/// EventSystem, and this project uses the Input System (1.19.0), so the module must be the Input-System one,
|
|
/// not the legacy StandaloneInputModule — without it the buttons are silently dead.
|
|
/// </summary>
|
|
public static class MenuUi
|
|
{
|
|
public static readonly Color Bg = new(0.04f, 0.05f, 0.07f, 0.96f);
|
|
public static readonly Color PanelBg = new(0.09f, 0.11f, 0.15f, 0.98f);
|
|
public static readonly Color Accent = new(0.30f, 0.85f, 1f, 1f); // Aether cyan
|
|
public static readonly Color TextCol = new(0.86f, 0.92f, 0.97f, 1f);
|
|
public static readonly Color SubCol = new(0.60f, 0.68f, 0.76f, 1f);
|
|
|
|
public static PanelSettings LoadPanelSettings()
|
|
=> Resources.Load<PanelSettings>("RuntimePanelSettings");
|
|
|
|
public static void EnsureEventSystem()
|
|
{
|
|
if (UnityEngine.Object.FindFirstObjectByType<EventSystem>() != null) return;
|
|
var go = new GameObject("EventSystem");
|
|
go.AddComponent<EventSystem>();
|
|
go.AddComponent<InputSystemUIInputModule>();
|
|
}
|
|
|
|
public static VisualElement FullScreenRoot(bool dim)
|
|
{
|
|
var root = new VisualElement();
|
|
root.style.position = Position.Absolute;
|
|
root.style.left = 0; root.style.right = 0; root.style.top = 0; root.style.bottom = 0;
|
|
root.style.alignItems = Align.Center;
|
|
root.style.justifyContent = Justify.Center;
|
|
if (dim) root.style.backgroundColor = Bg;
|
|
return root;
|
|
}
|
|
|
|
public static VisualElement Card(string titleText)
|
|
{
|
|
var card = new VisualElement();
|
|
card.style.backgroundColor = PanelBg;
|
|
card.style.paddingLeft = 28; card.style.paddingRight = 28;
|
|
card.style.paddingTop = 22; card.style.paddingBottom = 22;
|
|
card.style.minWidth = 380;
|
|
card.style.alignItems = Align.Stretch;
|
|
Round(card, 10);
|
|
Border(card, new Color(Accent.r, Accent.g, Accent.b, 0.25f), 1);
|
|
if (!string.IsNullOrEmpty(titleText)) card.Add(Title(titleText));
|
|
return card;
|
|
}
|
|
|
|
public static Label Title(string text)
|
|
{
|
|
var l = new Label(text);
|
|
l.style.unityFontStyleAndWeight = FontStyle.Bold;
|
|
l.style.fontSize = 26;
|
|
l.style.color = Accent;
|
|
l.style.unityTextAlign = TextAnchor.MiddleCenter;
|
|
l.style.marginBottom = 16;
|
|
return l;
|
|
}
|
|
|
|
public static Label Caption(string text)
|
|
{
|
|
var l = new Label(text);
|
|
l.style.fontSize = 13;
|
|
l.style.color = SubCol;
|
|
l.style.unityTextAlign = TextAnchor.MiddleCenter;
|
|
l.style.marginTop = 8; l.style.marginBottom = 6;
|
|
return l;
|
|
}
|
|
|
|
public static Button Button(string text, Action onClick)
|
|
{
|
|
var b = new Button(onClick) { text = text };
|
|
b.style.height = 40;
|
|
b.style.fontSize = 16;
|
|
b.style.marginTop = 5; b.style.marginBottom = 5;
|
|
b.style.color = TextCol;
|
|
b.style.backgroundColor = new Color(0.16f, 0.20f, 0.27f, 1f);
|
|
b.style.unityFontStyleAndWeight = FontStyle.Bold;
|
|
Round(b, 6);
|
|
Border(b, new Color(0f, 0f, 0f, 0f), 0);
|
|
return b;
|
|
}
|
|
|
|
public static Button SmallButton(string text, Action onClick)
|
|
{
|
|
var b = Button(text, onClick);
|
|
b.style.width = 36; b.style.height = 30;
|
|
b.style.marginLeft = 4; b.style.marginRight = 4;
|
|
return b;
|
|
}
|
|
|
|
public static void Round(VisualElement e, float r)
|
|
{
|
|
e.style.borderTopLeftRadius = r; e.style.borderTopRightRadius = r;
|
|
e.style.borderBottomLeftRadius = r; e.style.borderBottomRightRadius = r;
|
|
}
|
|
|
|
public static void Border(VisualElement e, Color c, float w)
|
|
{
|
|
e.style.borderLeftWidth = w; e.style.borderRightWidth = w;
|
|
e.style.borderTopWidth = w; e.style.borderBottomWidth = w;
|
|
e.style.borderLeftColor = c; e.style.borderRightColor = c;
|
|
e.style.borderTopColor = c; e.style.borderBottomColor = c;
|
|
}
|
|
}
|
|
}
|