Files
przygody-pana-cegly/scripts/UI/PauseMenu.cs
Gabriel Kaszewski f4411e05a3 fix: SpeedRunHud never detached from the autoload's signal
every level load left another handler attached to a freed HUD.
SpeedRunManager outlives the scene, so it kept calling them and each one
wrote to a disposed Label - thousands of ObjectDisposedException per
frame, growing with each load.

Latent all along: StartTimer was only ever called from StartNewGame, so
after a Continue the timer never ticked and the dead handlers never ran.
Calling StartTimer on Continue (needed for splits and best times) made
it visible.

Also stop the timer when leaving to the menu - StopTimer existed and had
no callers, so the run kept ticking in the main menu.
2026-07-28 20:00:55 +02:00

97 lines
3.0 KiB
C#

using Godot;
using Mr.BrickAdventures.Autoloads;
namespace Mr.BrickAdventures.scripts.UI;
public partial class PauseMenu : Control
{
[Export] public Control PauseMenuControl { get; set; }
[Export] public Control SettingsControl { get; set; }
[Export] public Button ResumeButton { get; set; }
[Export] public Button MainMenuButton { get; set; }
[Export] public Button QuitButton { get; set; }
[Export] public Button SettingsButton { get; set; }
[Export] public PackedScene MainMenuScene { get; set; }
private GameManager GameManager => GameManager.Instance;
private UIManager UIManager => UIManager.Instance;
public override void _Ready()
{
ResumeButton.FocusMode = Control.FocusModeEnum.All;
MainMenuButton.FocusMode = Control.FocusModeEnum.All;
QuitButton.FocusMode = Control.FocusModeEnum.All;
SettingsButton.FocusMode = Control.FocusModeEnum.All;
ResumeButton.Pressed += OnResumePressed;
MainMenuButton.Pressed += OnMainMenuPressed;
QuitButton.Pressed += OnQuitPressed;
SettingsButton.Pressed += OnSettingsPressed;
PauseMenuControl.Hide();
if (InputDeviceManager.Instance != null)
InputDeviceManager.Instance.DeviceChanged += OnDeviceChanged;
PauseMenuControl.VisibilityChanged += OnVisibilityChanged;
}
public override void _ExitTree()
{
if (InputDeviceManager.Instance != null)
InputDeviceManager.Instance.DeviceChanged -= OnDeviceChanged;
PauseMenuControl.VisibilityChanged -= OnVisibilityChanged;
}
private void OnVisibilityChanged()
{
if (PauseMenuControl.IsVisibleInTree() && InputDeviceManager.Instance?.IsPointerless == true)
GrabFirstFocus();
}
private void OnDeviceChanged(int device)
{
var d = (InputDeviceManager.InputDevice)device;
if (d != InputDeviceManager.InputDevice.Mouse && PauseMenuControl.IsVisibleInTree())
GrabFirstFocus();
}
private void GrabFirstFocus() => ResumeButton.GrabFocus();
public override void _UnhandledInput(InputEvent @event)
{
if (!@event.IsActionPressed("pause")) return;
if (UIManager.IsVisibleOnStack(PauseMenuControl))
OnResumePressed();
else
{
UIManager.PushScreen(PauseMenuControl);
GameManager.PauseGame();
}
}
private void OnSettingsPressed()
{
UIManager.PushScreen(SettingsControl);
GameManager.PauseGame();
}
private void OnQuitPressed()
{
GameManager.QuitGame();
}
private void OnMainMenuPressed()
{
GameManager.ResumeGame();
GameStateStore.Instance?.ResetSession();
// The run is over once you leave to the menu; otherwise the timer keeps ticking there.
SpeedRunManager.Instance?.StopTimer();
GetTree().ChangeSceneToPacked(MainMenuScene);
}
private void OnResumePressed()
{
UIManager.PopScreen();
GameManager.ResumeGame();
}
}