Skip to content

Commit 31040fc

Browse files
committed
rework scene menu scripts
1 parent f57279b commit 31040fc

5 files changed

Lines changed: 1094 additions & 170 deletions

File tree

Assets/QA/Tests/Core Platform Menu/Escape Menu.cs

Lines changed: 0 additions & 80 deletions
This file was deleted.
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
using TMPro;
2+
using UnityEngine;
3+
using UnityEngine.EventSystems;
4+
using UnityEngine.InputSystem;
5+
using UnityEngine.InputSystem.UI;
6+
using UnityEngine.SceneManagement;
7+
using UnityEngine.UI;
8+
9+
/// <summary>
10+
/// Persistent floating overlay that lets the player return to the main menu (build
11+
/// index 0) from any scene. Created automatically by <see cref="SceneMenu"/> when
12+
/// a scene is loaded and destroys itself when returning to the menu.
13+
/// </summary>
14+
public class ReturnToMenuOverlay : MonoBehaviour
15+
{
16+
static ReturnToMenuOverlay s_Instance;
17+
18+
InputAction m_BackAction;
19+
GameObject m_ConfirmPanel;
20+
Canvas m_Canvas;
21+
bool m_PanelVisible;
22+
23+
static readonly Color kOverlay = new Color(0f, 0f, 0f, 0.7f);
24+
static readonly Color kBtnNorm = new Color32(42, 42, 56, 230);
25+
static readonly Color kBtnHover = new Color32(60, 70, 100, 240);
26+
static readonly Color kPrimary = new Color32(80, 140, 255, 255);
27+
static readonly Color kText = new Color32(230, 230, 240, 255);
28+
static readonly Color kTextDim = new Color32(160, 160, 180, 255);
29+
30+
public static void Show()
31+
{
32+
if (s_Instance != null) return;
33+
var go = new GameObject("[ReturnToMenuOverlay]");
34+
DontDestroyOnLoad(go);
35+
s_Instance = go.AddComponent<ReturnToMenuOverlay>();
36+
}
37+
38+
public static void Hide()
39+
{
40+
if (s_Instance == null) return;
41+
Destroy(s_Instance.gameObject);
42+
s_Instance = null;
43+
}
44+
45+
void Awake()
46+
{
47+
BuildUI();
48+
SetupInput();
49+
SceneManager.sceneLoaded += OnSceneLoaded;
50+
}
51+
52+
void OnDestroy()
53+
{
54+
SceneManager.sceneLoaded -= OnSceneLoaded;
55+
m_BackAction?.Dispose();
56+
if (s_Instance == this) s_Instance = null;
57+
}
58+
59+
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
60+
{
61+
if (scene.buildIndex == 0)
62+
{
63+
Hide();
64+
return;
65+
}
66+
EnsureEventSystem();
67+
SetPanelVisible(false);
68+
}
69+
70+
#region Input
71+
72+
void SetupInput()
73+
{
74+
m_BackAction = new InputAction("BackToMenu", InputActionType.Button);
75+
m_BackAction.AddBinding("<Keyboard>/escape");
76+
m_BackAction.AddBinding("<Gamepad>/select");
77+
m_BackAction.performed += _ => TogglePanel();
78+
m_BackAction.Enable();
79+
}
80+
81+
void TogglePanel()
82+
{
83+
SetPanelVisible(!m_PanelVisible);
84+
}
85+
86+
void SetPanelVisible(bool visible)
87+
{
88+
m_PanelVisible = visible;
89+
if (m_ConfirmPanel != null)
90+
m_ConfirmPanel.SetActive(visible);
91+
}
92+
93+
#endregion
94+
95+
#region UI
96+
97+
void BuildUI()
98+
{
99+
// Canvas
100+
m_Canvas = gameObject.AddComponent<Canvas>();
101+
m_Canvas.renderMode = RenderMode.ScreenSpaceOverlay;
102+
m_Canvas.sortingOrder = 999;
103+
104+
var scaler = gameObject.AddComponent<CanvasScaler>();
105+
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
106+
scaler.referenceResolution = new Vector2(1920, 1080);
107+
scaler.matchWidthOrHeight = 0.5f;
108+
109+
gameObject.AddComponent<GraphicRaycaster>();
110+
111+
BuildMenuButton();
112+
BuildConfirmPanel();
113+
}
114+
115+
void BuildMenuButton()
116+
{
117+
var go = new GameObject("MenuBtn", typeof(RectTransform));
118+
go.transform.SetParent(transform, false);
119+
var img = go.AddComponent<Image>();
120+
img.color = kBtnNorm;
121+
122+
var rt = go.GetComponent<RectTransform>();
123+
rt.anchorMin = new Vector2(0, 1);
124+
rt.anchorMax = new Vector2(0, 1);
125+
rt.pivot = new Vector2(0, 1);
126+
rt.anchoredPosition = new Vector2(16, -16);
127+
rt.sizeDelta = new Vector2(120, 44);
128+
129+
var btn = go.AddComponent<Button>();
130+
btn.targetGraphic = img;
131+
var c = btn.colors;
132+
c.normalColor = kBtnNorm;
133+
c.highlightedColor = kBtnHover;
134+
c.pressedColor = kPrimary;
135+
c.fadeDuration = 0.08f;
136+
btn.colors = c;
137+
btn.onClick.AddListener(TogglePanel);
138+
139+
var txt = new GameObject("Text", typeof(RectTransform));
140+
txt.transform.SetParent(go.transform, false);
141+
var tmp = txt.AddComponent<TextMeshProUGUI>();
142+
tmp.text = "\u25C4 Menu";
143+
tmp.fontSize = 18;
144+
tmp.color = kText;
145+
tmp.alignment = TextAlignmentOptions.Center;
146+
tmp.raycastTarget = false;
147+
StretchRT(txt);
148+
}
149+
150+
void BuildConfirmPanel()
151+
{
152+
// Full-screen dimmer
153+
m_ConfirmPanel = new GameObject("ConfirmPanel", typeof(RectTransform));
154+
m_ConfirmPanel.transform.SetParent(transform, false);
155+
var dimmer = m_ConfirmPanel.AddComponent<Image>();
156+
dimmer.color = kOverlay;
157+
StretchRT(m_ConfirmPanel);
158+
159+
// Prevent clicks passing through
160+
m_ConfirmPanel.AddComponent<Button>().onClick.AddListener(() => SetPanelVisible(false));
161+
162+
// Center card
163+
var card = new GameObject("Card", typeof(RectTransform));
164+
card.transform.SetParent(m_ConfirmPanel.transform, false);
165+
var cardImg = card.AddComponent<Image>();
166+
cardImg.color = new Color32(32, 32, 44, 255);
167+
var cr = card.GetComponent<RectTransform>();
168+
cr.anchorMin = new Vector2(0.5f, 0.5f);
169+
cr.anchorMax = new Vector2(0.5f, 0.5f);
170+
cr.pivot = new Vector2(0.5f, 0.5f);
171+
cr.sizeDelta = new Vector2(420, 200);
172+
173+
// Title
174+
var title = new GameObject("Title", typeof(RectTransform));
175+
title.transform.SetParent(card.transform, false);
176+
var titleTMP = title.AddComponent<TextMeshProUGUI>();
177+
titleTMP.text = "Return to Main Menu?";
178+
titleTMP.fontSize = 24;
179+
titleTMP.color = kText;
180+
titleTMP.alignment = TextAlignmentOptions.Center;
181+
titleTMP.raycastTarget = false;
182+
var trt = title.GetComponent<RectTransform>();
183+
trt.anchorMin = new Vector2(0, 0.55f);
184+
trt.anchorMax = Vector2.one;
185+
trt.offsetMin = new Vector2(20, 0);
186+
trt.offsetMax = new Vector2(-20, -16);
187+
188+
// Hint
189+
var hint = new GameObject("Hint", typeof(RectTransform));
190+
hint.transform.SetParent(card.transform, false);
191+
var hintTMP = hint.AddComponent<TextMeshProUGUI>();
192+
hintTMP.text = "Press Escape again or tap outside to cancel";
193+
hintTMP.fontSize = 13;
194+
hintTMP.color = kTextDim;
195+
hintTMP.alignment = TextAlignmentOptions.Center;
196+
hintTMP.raycastTarget = false;
197+
var hrt = hint.GetComponent<RectTransform>();
198+
hrt.anchorMin = new Vector2(0, 0.38f);
199+
hrt.anchorMax = new Vector2(1, 0.55f);
200+
hrt.offsetMin = new Vector2(20, 0);
201+
hrt.offsetMax = new Vector2(-20, 0);
202+
203+
// Buttons row
204+
var row = new GameObject("Buttons", typeof(RectTransform));
205+
row.transform.SetParent(card.transform, false);
206+
var hlg = row.AddComponent<HorizontalLayoutGroup>();
207+
hlg.childControlWidth = true;
208+
hlg.childControlHeight = true;
209+
hlg.childForceExpandWidth = true;
210+
hlg.childForceExpandHeight = true;
211+
hlg.spacing = 16;
212+
hlg.padding = new RectOffset(24, 24, 0, 0);
213+
var rrt = row.GetComponent<RectTransform>();
214+
rrt.anchorMin = Vector2.zero;
215+
rrt.anchorMax = new Vector2(1, 0.38f);
216+
rrt.offsetMin = new Vector2(0, 16);
217+
rrt.offsetMax = Vector2.zero;
218+
219+
MakeDialogButton(row.transform, "Cancel", new Color32(52, 52, 68, 255), kTextDim,
220+
() => SetPanelVisible(false));
221+
MakeDialogButton(row.transform, "Return to Menu", kPrimary, Color.white,
222+
ReturnToMenu);
223+
224+
m_ConfirmPanel.SetActive(false);
225+
}
226+
227+
void MakeDialogButton(Transform parent, string label, Color bg, Color textColor, UnityEngine.Events.UnityAction action)
228+
{
229+
var go = new GameObject(label, typeof(RectTransform));
230+
go.transform.SetParent(parent, false);
231+
var img = go.AddComponent<Image>();
232+
img.color = bg;
233+
234+
var btn = go.AddComponent<Button>();
235+
btn.targetGraphic = img;
236+
btn.onClick.AddListener(action);
237+
238+
var txt = new GameObject("Text", typeof(RectTransform));
239+
txt.transform.SetParent(go.transform, false);
240+
var tmp = txt.AddComponent<TextMeshProUGUI>();
241+
tmp.text = label;
242+
tmp.fontSize = 17;
243+
tmp.color = textColor;
244+
tmp.alignment = TextAlignmentOptions.Center;
245+
tmp.raycastTarget = false;
246+
StretchRT(txt);
247+
}
248+
249+
#endregion
250+
251+
#region Navigation
252+
253+
void ReturnToMenu()
254+
{
255+
SceneManager.LoadScene(0);
256+
}
257+
258+
static void EnsureEventSystem()
259+
{
260+
if (FindObjectOfType<EventSystem>() != null) return;
261+
var go = new GameObject("EventSystem");
262+
DontDestroyOnLoad(go);
263+
go.AddComponent<EventSystem>();
264+
go.AddComponent<InputSystemUIInputModule>();
265+
}
266+
267+
#endregion
268+
269+
static void StretchRT(GameObject go)
270+
{
271+
var r = go.GetComponent<RectTransform>();
272+
r.anchorMin = Vector2.zero;
273+
r.anchorMax = Vector2.one;
274+
r.sizeDelta = Vector2.zero;
275+
r.anchoredPosition = Vector2.zero;
276+
}
277+
}

Assets/QA/Tests/Core Platform Menu/Scene Loader.cs

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)