Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Assets/Scripts/UI/MainGame/PauseMenu.uxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance"
engine="UnityEngine.UIElements" editor="UnityEditor.UIElements"
noNamespaceSchemaLocation="../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
<Style src="project://database/Assets/DesignSystem/Resources/UI/Styles/DesignSystem/DesignSystem.uss"/>
<ui:Template name="pauseOverlayTemplate" src="project://database/Assets/Scripts/UI/Common/PauseOverlay.uxml"/>
<ui:Template name="settingsOverlayTemplate" src="project://database/Assets/Scripts/UI/Common/SettingsOverlay.uxml"/>

<ui:VisualElement name="pause-overlay-host"
style="position: absolute; left: 0; right: 0; top: 0; bottom: 0; display: none;">
<ui:Instance template="pauseOverlayTemplate"
style="position: absolute; left: 0; right: 0; top: 0; bottom: 0;"/>
</ui:VisualElement>

<ui:VisualElement name="settings-overlay-host"
style="position: absolute; left: 0; right: 0; top: 0; bottom: 0; display: none;">
<ui:Instance template="settingsOverlayTemplate"
style="position: absolute; left: 0; right: 0; top: 0; bottom: 0;"/>
</ui:VisualElement>
</ui:UXML>
3 changes: 3 additions & 0 deletions Assets/Scripts/UI/MainGame/PauseMenu.uxml.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

147 changes: 147 additions & 0 deletions Assets/Scripts/UI/MainGame/PauseMenuController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
using System;
using Core.Constants;
using Events.Game;
using Events.UI;
using UI.Common;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UIElements;

namespace UI.MainGame
{
[RequireComponent(typeof(UIDocument))]
public class PauseMenuController : MonoBehaviour
{
[SerializeField] private UIDocument uiDocument;

[SerializeField] private PointerOverUiEventChannel pointerOverUiChannel;

[SerializeField] private PauseStateEventChannel pauseStateChannel;

private bool _isPaused;
private VisualElement _pauseOverlay;
private VisualElement _pauseOverlayHost;
private bool _pauseUiInitialized;
private bool _pointerBlockersRegistered;
private VisualElement _root;
private SettingsPanelController _settingsPanelController;
private UiPointerTracker _uiPointerTracker;

private void Awake()
{
if (uiDocument == null)
uiDocument = GetComponent<UIDocument>();
}

private void LateUpdate()
{
if (!Input.GetKeyDown(KeyCode.Escape))
return;

if (_settingsPanelController is { IsOpen: true })
{
_settingsPanelController.Hide();
return;
}

SetPaused(!_isPaused);
}

private void OnEnable()
{
if (uiDocument == null || uiDocument.rootVisualElement == null)
return;
Comment thread
lmProgramming marked this conversation as resolved.

_root = uiDocument.rootVisualElement;
InitializePauseUi();
RegisterUiPointerBlockers();
}

private void OnDisable()
{
SetPaused(false);
}

private void InitializePauseUi()
{
if (_pauseUiInitialized || _root == null)
return;

_pauseOverlay = _root.Q<VisualElement>(SharedUiElementNames.Pause.Overlay);
_pauseOverlayHost = _root.Q<VisualElement>(SharedUiElementNames.Pause.OverlayHost);
var title = _root.Q<Label>(SharedUiElementNames.Pause.Title);
var resumeButton = _root.Q<Button>(SharedUiElementNames.Pause.ResumeButton);
var settingsButton = _root.Q<Button>(SharedUiElementNames.Pause.SettingsButton);
var quitButton = _root.Q<Button>(SharedUiElementNames.Pause.QuitButton);

if (title == null || resumeButton == null || settingsButton == null || quitButton == null)
throw new InvalidOperationException("[PauseMenuController] Pause elements missing in PauseMenu UXML.");

title.text = "Paused";
if (_pauseOverlayHost != null)
_pauseOverlayHost.style.display = DisplayStyle.None;
_pauseOverlay.style.display = DisplayStyle.None;
resumeButton.clicked += () => { SetPaused(false); };
Comment thread
lmProgramming marked this conversation as resolved.
settingsButton.clicked += () => { _settingsPanelController.Toggle(); };
quitButton.clicked += QuitToMainMenu;
_settingsPanelController = new SettingsPanelController(_root, false);
_pauseUiInitialized = true;
}

private void RegisterUiPointerBlockers()
{
if (_pointerBlockersRegistered || _root == null)
return;

if (pointerOverUiChannel == null)
throw new InvalidOperationException(
"[PauseMenuController] Pointer Over UI event channel is not assigned. " +
"Assign the SAME PointerOverUiEventChannel asset that is set on GameProjectInstaller.");

_uiPointerTracker = new UiPointerTracker(pointerOverUiChannel);
TrackPointerBlocker(SharedUiElementNames.Pause.OverlayHost);
TrackPointerBlocker(SharedUiElementNames.Settings.OverlayHost);
_pointerBlockersRegistered = true;
}

private void TrackPointerBlocker(string elementName)
{
var element = _root.Q<VisualElement>(elementName);
_uiPointerTracker.Track(element);
}

private void SetPaused(bool paused)
{
if (_isPaused == paused)
return;

_isPaused = paused;
Time.timeScale = paused ? 0f : 1f;

if (pauseStateChannel)
pauseStateChannel.Raise(paused);

if (_pauseOverlayHost != null)
_pauseOverlayHost.style.display = paused ? DisplayStyle.Flex : DisplayStyle.None;
if (_pauseOverlay != null)
_pauseOverlay.style.display = paused ? DisplayStyle.Flex : DisplayStyle.None;

if (!paused && _settingsPanelController != null && _settingsPanelController.IsOpen)
_settingsPanelController.Hide();

// A full-screen overlay that hides under a stationary pointer never emits PointerLeave,
// so explicitly clear its pointer-over-UI state when leaving the paused state.
if (!paused && _uiPointerTracker != null)
{
_uiPointerTracker.Release(_pauseOverlayHost);
_uiPointerTracker.Release(_root?.Q<VisualElement>(SharedUiElementNames.Settings.OverlayHost));
}
}

private static void QuitToMainMenu()
{
Time.timeScale = 1f;
SceneManager.LoadScene(SceneNames.MainMenu);
}
}
}
3 changes: 3 additions & 0 deletions Assets/Scripts/UI/MainGame/PauseMenuController.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading