Add Resume/Exit buttons to pause menu, handle logic for returning to main menu and starting a new game
This commit is contained in:
@@ -24,6 +24,8 @@ public partial class AppLogic
|
||||
|
||||
public readonly record struct ShowMainMenu;
|
||||
|
||||
public readonly record struct CloseGame;
|
||||
|
||||
public readonly record struct ExitGame;
|
||||
|
||||
public readonly record struct GameOver;
|
||||
|
||||
@@ -9,7 +9,7 @@ public partial class AppLogic
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record GameStarted : State
|
||||
public partial record GameStarted : State, IGet<Input.QuitGame>
|
||||
{
|
||||
public GameStarted()
|
||||
{
|
||||
@@ -26,6 +26,11 @@ public partial class AppLogic
|
||||
OnDetach(() => Get<IAppRepo>().GameExited -= OnGameExited);
|
||||
}
|
||||
|
||||
public Transition On(in Input.QuitGame input)
|
||||
{
|
||||
Output(new Output.CloseGame());
|
||||
return To<MainMenu>();
|
||||
}
|
||||
public void OnGameExited() => Input(new Input.QuitGame());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,14 @@ public partial class GameState
|
||||
|
||||
public readonly record struct LoadGame;
|
||||
|
||||
public readonly record struct ExitGame;
|
||||
|
||||
public readonly record struct LoadNextFloor;
|
||||
|
||||
public readonly record struct InventoryButtonPressed;
|
||||
|
||||
public readonly record struct InteractButtonPressed;
|
||||
|
||||
public readonly record struct PauseButtonPressed;
|
||||
|
||||
public readonly record struct DebugButtonPressed;
|
||||
|
||||
@@ -6,6 +6,8 @@ public partial class GameState
|
||||
{
|
||||
public readonly record struct InitializeGame;
|
||||
|
||||
public readonly record struct ExitGame;
|
||||
|
||||
public readonly record struct LoadGameFromFile;
|
||||
|
||||
public readonly record struct OpenInventoryMenu;
|
||||
|
||||
@@ -8,9 +8,9 @@ public partial class GameState
|
||||
public partial record State
|
||||
{
|
||||
[Meta, LogicBlock(typeof(State), Diagram = true)]
|
||||
public partial record InventoryScreen : State, IGet<Input.InventoryButtonPressed>
|
||||
public partial record InventoryScreen : State, IGet<Input.InteractButtonPressed>
|
||||
{
|
||||
public Transition On(in Input.InventoryButtonPressed input)
|
||||
public Transition On(in Input.InteractButtonPressed input)
|
||||
{
|
||||
Output(new Output.CloseInventoryMenu());
|
||||
return To<InGame>();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
using static Zennysoft.Ma.Adapter.GameState.Output;
|
||||
|
||||
namespace Zennysoft.Ma.Adapter;
|
||||
|
||||
@@ -8,13 +9,20 @@ public partial class GameState
|
||||
public partial record State
|
||||
{
|
||||
[Meta, LogicBlock(typeof(State), Diagram = true)]
|
||||
public partial record PauseScreen : State, IGet<Input.PauseButtonPressed>
|
||||
public partial record PauseScreen : State, IGet<Input.PauseButtonPressed>, IGet<Input.ExitGame>
|
||||
{
|
||||
public Transition On(in Input.PauseButtonPressed input)
|
||||
{
|
||||
Output(new Output.ClosePauseScreen());
|
||||
return To<InGame>();
|
||||
}
|
||||
|
||||
public Transition On(in Input.ExitGame input)
|
||||
{
|
||||
Output(new Output.ClosePauseScreen());
|
||||
Output(new Output.ExitGame());
|
||||
return To<State>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Collections;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using NathanHoad;
|
||||
using SimpleInjector.Lifestyles;
|
||||
using System;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Zennysoft.Game.Abstractions;
|
||||
using Zennysoft.Game.Implementation;
|
||||
using Zennysoft.Ma.Adapter;
|
||||
using static Zennysoft.Game.Ma.SceneLoader;
|
||||
using static Zennysoft.Ma.Adapter.AppLogic.State;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
@@ -37,8 +31,6 @@ public partial class App : Node, IApp
|
||||
|
||||
[Node] private GalleryMenu GalleryMenu { get; set; }
|
||||
|
||||
public IInstantiator Instantiator { get; set; } = default!;
|
||||
|
||||
IAppRepo IProvide<IAppRepo>.Value() => AppRepo;
|
||||
|
||||
public IAppRepo AppRepo { get; set; } = default!;
|
||||
@@ -57,9 +49,6 @@ public partial class App : Node, IApp
|
||||
private IGame _game;
|
||||
private IDataViewer _enemyViewer;
|
||||
|
||||
private event Action OnGameLoaded;
|
||||
private event Action OnEnemyViewerLoaded;
|
||||
|
||||
private double _reportedProgress = 0;
|
||||
|
||||
public void Initialize()
|
||||
@@ -110,6 +99,11 @@ public partial class App : Node, IApp
|
||||
this.Provide();
|
||||
}
|
||||
|
||||
private void GameExitRequested()
|
||||
{
|
||||
AppLogic.Input(new AppLogic.Input.QuitGame());
|
||||
}
|
||||
|
||||
private void DeleteSaveData()
|
||||
{
|
||||
var saveFileManager = _container.GetInstance<ISaveFileManager>();
|
||||
@@ -150,27 +144,31 @@ public partial class App : Node, IApp
|
||||
})
|
||||
.Handle((in AppLogic.Output.SetupGameScene _) =>
|
||||
{
|
||||
LoadingScreen.Show();
|
||||
LoadGame(GAME_SCENE_PATH);
|
||||
MainMenu.ReleaseFocus();
|
||||
MainMenu.Hide();
|
||||
})
|
||||
.Handle((in AppLogic.Output.ShowMainMenu _) =>
|
||||
{
|
||||
})
|
||||
.Handle((in AppLogic.Output.ShowGame _) =>
|
||||
.Handle((in AppLogic.Output.CloseGame _) =>
|
||||
{
|
||||
LoadingScreen.Hide();
|
||||
_game.GameExitRequested -= GameExitRequested;
|
||||
MainMenu.StartGameButton.GrabFocus();
|
||||
_game.CallDeferred(MethodName.QueueFree, []);
|
||||
GetTree().Paused = false;
|
||||
})
|
||||
.Handle((in AppLogic.Output.StartLoadingSaveFile _) =>
|
||||
{
|
||||
})
|
||||
.Handle((in AppLogic.Output.EnemyViewerOpened _) =>
|
||||
{
|
||||
LoadingScreen.Show();
|
||||
LoadEnemyViewer(ENEMY_VIEWER_PATH);
|
||||
MainMenu.ReleaseFocus();
|
||||
MainMenu.Hide();
|
||||
})
|
||||
.Handle((in AppLogic.Output.EnemyViewerExited _) =>
|
||||
{
|
||||
LoadingScreen.Hide();
|
||||
if (_enemyViewer != null && _enemyViewer is DataViewer enemyViewer)
|
||||
enemyViewer.CallDeferred(MethodName.QueueFree);
|
||||
MainMenu.Show();
|
||||
@@ -202,6 +200,7 @@ public partial class App : Node, IApp
|
||||
{
|
||||
var scene = await LoadSceneInternal(sceneName);
|
||||
_game = scene as IGame;
|
||||
_game.GameExitRequested += GameExitRequested;
|
||||
await ToSignal(GetTree().CreateTimer(0.8f), "timeout");
|
||||
CallDeferred(MethodName.AddChild, scene);
|
||||
}
|
||||
@@ -216,6 +215,7 @@ public partial class App : Node, IApp
|
||||
|
||||
private async Task<Node> LoadSceneInternal(string sceneName)
|
||||
{
|
||||
LoadingScreen.Show();
|
||||
LoadingScreen.ProgressBar.Value = 0;
|
||||
var sceneLoader = new SceneLoader();
|
||||
CallDeferred(MethodName.AddChild, sceneLoader);
|
||||
|
||||
@@ -10,12 +10,13 @@
|
||||
process_mode = 3
|
||||
script = ExtResource("1_rt73h")
|
||||
|
||||
[node name="LoadingScreen" parent="." instance=ExtResource("3_3st5l")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="MainMenu" parent="." instance=ExtResource("2_1uiag")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="LoadingScreen" parent="." instance=ExtResource("3_3st5l")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
|
||||
[node name="OptionsMenu" parent="." instance=ExtResource("2_v0mgf")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
|
||||
@@ -56,6 +56,8 @@ public partial class Game : Node3D, IGame
|
||||
|
||||
[Signal]
|
||||
public delegate void SaveFileLoadedEventHandler();
|
||||
|
||||
public event Action GameExitRequested;
|
||||
#endregion
|
||||
|
||||
public RescuedItemDatabase RescuedItems { get; set; } = default!;
|
||||
@@ -174,6 +176,8 @@ public partial class Game : Node3D, IGame
|
||||
GameOverMenu.NewGame += OnNewGame;
|
||||
GameOverMenu.QuitGame += OnQuit;
|
||||
|
||||
PauseMenu.ExitGamePressed += OnQuit;
|
||||
|
||||
GameRepo.IsPaused.Sync += IsPaused_Sync;
|
||||
InGameUI.PlayerInfoUI.Activate();
|
||||
}
|
||||
@@ -252,6 +256,12 @@ public partial class Game : Node3D, IGame
|
||||
{
|
||||
if (@event.IsActionPressed(GameInputs.Debug))
|
||||
GameState.Input(new GameState.Input.DebugButtonPressed());
|
||||
if (@event.IsActionPressed(GameInputs.Pause))
|
||||
GameState.Input(new GameState.Input.PauseButtonPressed());
|
||||
if (Input.IsActionJustPressed(GameInputs.Inventory))
|
||||
GameState.Input(new GameState.Input.InventoryButtonPressed());
|
||||
if (Input.IsActionJustPressed(GameInputs.Interact))
|
||||
GameState.Input(new GameState.Input.InteractButtonPressed());
|
||||
}
|
||||
|
||||
private void HandleGameLogic()
|
||||
@@ -280,12 +290,13 @@ public partial class Game : Node3D, IGame
|
||||
})
|
||||
.Handle((in GameState.Output.OpenInventoryMenu _) =>
|
||||
{
|
||||
//InGameUI.InventoryMenu.RefreshInventoryScreen();
|
||||
GameRepo.Pause();
|
||||
InGameUI.InventoryMenu.Show();
|
||||
InGameUI.InventoryMenu.SetProcessInput(true);
|
||||
})
|
||||
.Handle((in GameState.Output.CloseInventoryMenu _) =>
|
||||
{
|
||||
GameRepo.Resume();
|
||||
InGameUI.InventoryMenu.Hide();
|
||||
InGameUI.InventoryMenu.SetProcessInput(false);
|
||||
})
|
||||
@@ -337,6 +348,10 @@ public partial class Game : Node3D, IGame
|
||||
}
|
||||
LoadNextLevel.FadeOut();
|
||||
})
|
||||
.Handle((in GameState.Output.ExitGame _) =>
|
||||
{
|
||||
OnQuit();
|
||||
})
|
||||
.Handle((in GameState.Output.GameOver _) =>
|
||||
{
|
||||
//GameRepo.Pause();
|
||||
@@ -507,7 +522,7 @@ public partial class Game : Node3D, IGame
|
||||
LoadNextLevel.Hide();
|
||||
}
|
||||
|
||||
private void OnQuit() => GetTree().Root.QueueFree();
|
||||
private void OnQuit() => GameExitRequested?.Invoke();
|
||||
|
||||
public void OnExitTree()
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Zennysoft.Game.Ma;
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.SaveFileBuilder;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Zennysoft.Ma.Adapter;
|
||||
|
||||
@@ -30,4 +31,6 @@ public interface IGame : IProvide<IGame>, IProvide<IGameRepo>, IProvide<IPlayer>
|
||||
public Task Save();
|
||||
|
||||
public QuestData QuestData { get; }
|
||||
|
||||
public event Action GameExitRequested;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1ctjd"]
|
||||
|
||||
[node name="Control" type="Control"]
|
||||
process_mode = 3
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
|
||||
@@ -60,5 +60,14 @@ public partial class GalleryMenu : Control
|
||||
BackButton.Pressed += BackButton_Pressed;
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
|
||||
if (@event.IsActionPressed(GameInputs.Interact))
|
||||
BackButton.GrabFocus();
|
||||
}
|
||||
|
||||
private void BackButton_Pressed() => EmitSignal(SignalName.GalleryExited);
|
||||
}
|
||||
|
||||
@@ -57,13 +57,4 @@ public partial class InGameUI : Control, IInGameUI
|
||||
InventoryMenu.Hide();
|
||||
InventoryMenu.SetProcessInput(false);
|
||||
}
|
||||
|
||||
public override void _UnhandledInput(InputEvent @event)
|
||||
{
|
||||
if (@event.IsActionPressed(GameInputs.Inventory) && !InventoryMenu.Visible)
|
||||
{
|
||||
GD.Print("Inventory button pressed");
|
||||
InGameUILogic.Input(new InGameUILogic.Input.ShowInventory());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
SfxDatabase.Instance.Play(SoundEffect.MoveUI);
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
public override void _UnhandledInput(InputEvent @event)
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
@@ -108,12 +108,6 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
if ((!Input.IsActionJustPressed(GameInputs.UiUp) && Input.IsActionPressed(GameInputs.UiUp)) || (!Input.IsActionJustPressed(GameInputs.UiDown) && Input.IsActionPressed(GameInputs.UiDown)))
|
||||
AcceptEvent();
|
||||
|
||||
if (Input.IsActionJustPressed(GameInputs.Inventory) && !(UseButton.HasFocus() || DropButton.HasFocus() || ThrowButton.HasFocus()))
|
||||
{
|
||||
SfxDatabase.Instance.Play(SoundEffect.CancelUI);
|
||||
AcceptEvent();
|
||||
_gameRepo.CloseInventory();
|
||||
}
|
||||
if (Input.IsActionJustPressed(GameInputs.UiCancel) && (UseButton.HasFocus() || DropButton.HasFocus() || ThrowButton.HasFocus()))
|
||||
{
|
||||
SfxDatabase.Instance.Play(SoundEffect.CancelUI);
|
||||
@@ -153,6 +147,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
}
|
||||
else
|
||||
{
|
||||
SfxDatabase.Instance.Play(SoundEffect.CancelUI);
|
||||
_enableMenuSound = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using Chickensoft.AutoInject;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
public interface IPauseMenu : IControl
|
||||
@@ -10,6 +11,8 @@ public interface IPauseMenu : IControl
|
||||
void FadeOut();
|
||||
event PauseMenu.UnpauseButtonPressedEventHandler UnpauseButtonPressed;
|
||||
event PauseMenu.TransitionCompletedEventHandler TransitionCompleted;
|
||||
|
||||
public event Action ExitGamePressed;
|
||||
}
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
@@ -24,14 +27,32 @@ public partial class PauseMenu : Control, IPauseMenu
|
||||
|
||||
[Node] public IAnimationPlayer AnimationPlayer { get; set; } = default!;
|
||||
|
||||
[Node] public Button ResumeButton { get; set; } = default!;
|
||||
[Node] public Button ExitButton { get; set; } = default!;
|
||||
|
||||
public event Action ExitGamePressed;
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
AnimationPlayer.AnimationFinished += OnAnimationFinished;
|
||||
ResumeButton.Pressed += ResumeButton_Pressed;
|
||||
ExitButton.Pressed += ExitButton_Pressed;
|
||||
}
|
||||
|
||||
public void FadeIn() => AnimationPlayer.Play("fade_in");
|
||||
private void ExitButton_Pressed() => ExitGamePressed?.Invoke();
|
||||
private void ResumeButton_Pressed() => FadeOut();
|
||||
public void FadeIn()
|
||||
{
|
||||
ResumeButton.GrabFocus();
|
||||
AnimationPlayer.Play("fade_in");
|
||||
}
|
||||
|
||||
public void FadeOut() => AnimationPlayer.Play("fade_out");
|
||||
public void FadeOut()
|
||||
{
|
||||
ResumeButton.ReleaseFocus();
|
||||
ExitButton.ReleaseFocus();
|
||||
AnimationPlayer.Play("fade_out");
|
||||
}
|
||||
|
||||
public override void _UnhandledInput(InputEvent @event)
|
||||
{
|
||||
@@ -41,5 +62,7 @@ public partial class PauseMenu : Control, IPauseMenu
|
||||
|
||||
public void OnAnimationFinished(StringName name)
|
||||
{
|
||||
if (name == "fade_out")
|
||||
Hide();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://blbqgw3wosc1w"]
|
||||
[gd_scene load_steps=9 format=3 uid="uid://blbqgw3wosc1w"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cbal5oeaha4nx" path="res://src/ui/pause_menu/PauseMenu.cs" id="1_1mfd6"]
|
||||
[ext_resource type="FontFile" uid="uid://beh6d5lo5ihq0" path="res://src/ui/fonts/georgiai.ttf" id="2_o1qdr"]
|
||||
[ext_resource type="StyleBox" uid="uid://bxuy4tnftibfq" path="res://src/options/SelectedOptionsBox.tres" id="2_xhp56"]
|
||||
[ext_resource type="StyleBox" uid="uid://bl15q835s4ene" path="res://src/options/UnselectedOptionsBox.tres" id="3_o1qdr"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_f1eqn"]
|
||||
length = 0.001
|
||||
@@ -62,6 +67,7 @@ anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_1mfd6")
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
@@ -77,3 +83,53 @@ anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="ResumeButton" type="Button" parent="CenterContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("2_o1qdr")
|
||||
theme_override_font_sizes/font_size = 38
|
||||
theme_override_styles/focus = ExtResource("2_xhp56")
|
||||
theme_override_styles/disabled_mirrored = ExtResource("3_o1qdr")
|
||||
theme_override_styles/disabled = ExtResource("3_o1qdr")
|
||||
theme_override_styles/hover_pressed_mirrored = ExtResource("3_o1qdr")
|
||||
theme_override_styles/hover_pressed = ExtResource("3_o1qdr")
|
||||
theme_override_styles/hover_mirrored = ExtResource("3_o1qdr")
|
||||
theme_override_styles/hover = ExtResource("3_o1qdr")
|
||||
theme_override_styles/pressed_mirrored = ExtResource("3_o1qdr")
|
||||
theme_override_styles/pressed = ExtResource("3_o1qdr")
|
||||
theme_override_styles/normal_mirrored = ExtResource("3_o1qdr")
|
||||
theme_override_styles/normal = ExtResource("3_o1qdr")
|
||||
text = "Resume"
|
||||
flat = true
|
||||
|
||||
[node name="ExitButton" type="Button" parent="CenterContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("2_o1qdr")
|
||||
theme_override_font_sizes/font_size = 38
|
||||
theme_override_styles/focus = ExtResource("2_xhp56")
|
||||
theme_override_styles/disabled_mirrored = ExtResource("3_o1qdr")
|
||||
theme_override_styles/disabled = ExtResource("3_o1qdr")
|
||||
theme_override_styles/hover_pressed_mirrored = ExtResource("3_o1qdr")
|
||||
theme_override_styles/hover_pressed = ExtResource("3_o1qdr")
|
||||
theme_override_styles/hover_mirrored = ExtResource("3_o1qdr")
|
||||
theme_override_styles/hover = ExtResource("3_o1qdr")
|
||||
theme_override_styles/pressed_mirrored = ExtResource("3_o1qdr")
|
||||
theme_override_styles/pressed = ExtResource("3_o1qdr")
|
||||
theme_override_styles/normal_mirrored = ExtResource("3_o1qdr")
|
||||
theme_override_styles/normal = ExtResource("3_o1qdr")
|
||||
text = "Exit Game"
|
||||
flat = true
|
||||
|
||||
Reference in New Issue
Block a user