Refactor: reorganize scripts with domain-driven design structure

Move all C# scripts from flat structure to organized folders:
- Core/ for game logic (Game, GameState, GameSettings)
- UI/Menus/ and UI/Dialogs/ for user interface
- Systems/ for reusable systems (Save, Localization)
- Data/ for data models and configuration
- Added framework for future: Gameplay/, Story/, Modding/

Update all .tscn scene files to reference new script paths.
Fix timing issue in AdvancedSaveDialog focus handling.
This commit is contained in:
Björn Blomberg
2025-10-17 14:50:40 +02:00
parent 74062a37d6
commit ed4ce28921
41 changed files with 173 additions and 8 deletions

View File

@@ -0,0 +1,310 @@
using Godot;
namespace TheGame
{
public partial class AdvancedSaveDialog : AcceptDialog
{
private LineEdit _nameInput;
private CheckBox _newInstanceCheck;
private Label _infoLabel;
private Game _gameController;
private SaveData _existingSaveData;
public override void _Ready()
{
// Sätt process mode så att dialogen fungerar när spelet är pausat
ProcessMode = ProcessModeEnum.WhenPaused;
var loc = LocalizationManager.Instance;
Title = loc.GetText("save_dialog_title");
// Kontrollera om det finns befintlig save för denna seed
var saveManager = new SaveManager();
if (GameState.CurrentGameSeed != null)
{
_existingSaveData = saveManager.FindSaveDataBySeed(GameState.CurrentGameSeed);
}
CreateDialogContent();
// Sätt process mode på alla child nodes
SetProcessModeRecursive(this, ProcessModeEnum.WhenPaused);
}
private void CreateDialogContent()
{
var vbox = new VBoxContainer();
if (_existingSaveData == null || _existingSaveData.Instances.Count == 0)
{
// Första gången man sparar detta spel - bara namn input
CreateFirstTimeSaveUI(vbox);
}
else
{
// Det finns befintliga saves - visa alternativ
CreateExistingSaveUI(vbox);
}
AddChild(vbox);
}
private void CreateFirstTimeSaveUI(VBoxContainer vbox)
{
var loc = LocalizationManager.Instance;
var infoLabel = new Label();
infoLabel.Text = "This is your first save for this game.";
infoLabel.AutowrapMode = TextServer.AutowrapMode.WordSmart;
vbox.AddChild(infoLabel);
var separator = new HSeparator();
vbox.AddChild(separator);
// Save name input
var nameLabel = new Label();
nameLabel.Text = loc.GetText("save_dialog_enter_name");
vbox.AddChild(nameLabel);
_nameInput = new LineEdit();
_nameInput.PlaceholderText = loc.GetText("save_dialog_placeholder");
_nameInput.Text = $"Save {System.DateTime.Now:HH:mm:ss}";
vbox.AddChild(_nameInput);
// Anslut signaler
Confirmed += OnSaveConfirmed;
// Fokusera på text input - skjut upp till nästa frame
CallDeferred(nameof(FocusNameInput));
}
private void CreateExistingSaveUI(VBoxContainer vbox)
{
var latestInstance = _existingSaveData.GetLatestInstance();
var infoLabel = new Label();
infoLabel.Text = $"Game Seed: {_existingSaveData.GameSeed.ToString()}\nExisting saves: {_existingSaveData.Instances.Count}\nLatest: {latestInstance.DisplayName} ({latestInstance.GetFormattedGameTime()})";
infoLabel.AutowrapMode = TextServer.AutowrapMode.WordSmart;
vbox.AddChild(infoLabel);
var separator = new HSeparator();
vbox.AddChild(separator);
// Button för att skriva över senaste save
var overwriteButton = new Button();
overwriteButton.Text = "Save over the last save point";
overwriteButton.CustomMinimumSize = new Vector2(0, 40);
overwriteButton.Pressed += OnOverwriteLatestPressed;
vbox.AddChild(overwriteButton);
// Button för att skapa ny save point
var newSaveButton = new Button();
newSaveButton.Text = "Save a new save point";
newSaveButton.CustomMinimumSize = new Vector2(0, 40);
newSaveButton.Pressed += OnNewSavePressed;
vbox.AddChild(newSaveButton);
// Dölj standard OK-knappen
GetOkButton().Visible = false;
}
public void Initialize(Game gameController)
{
_gameController = gameController;
}
private void ShowErrorDialog(string message)
{
var errorDialog = new AcceptDialog();
errorDialog.DialogText = message;
errorDialog.Title = "Save Error";
errorDialog.ProcessMode = ProcessModeEnum.WhenPaused;
GetTree().Root.AddChild(errorDialog);
errorDialog.PopupCentered();
}
private void OnOverwriteLatestPressed()
{
// Skriv över senaste save utan att fråga om namn
if (_gameController != null)
{
var saveManager = new SaveManager();
float currentTime = _gameController.GetGameTime();
bool saveSuccess = saveManager.SaveGame(currentTime, "", GameState.CurrentGameSeed, true); // overwriteLatest = true
if (saveSuccess)
{
GameState.MarkProgressAsSaved(currentTime);
_gameController.TogglePause();
}
else
{
ShowErrorDialog("Failed to save the game. Please try again.");
return;
}
}
QueueFree();
}
private void OnNewSavePressed()
{
// Visa namn-input dialog för ny save point
ShowNameInputDialog();
}
private void ShowNameInputDialog()
{
// Rensa nuvarande innehåll
foreach (Node child in GetChildren())
{
if (child != GetOkButton())
{
child.QueueFree();
}
}
var vbox = new VBoxContainer();
var loc = LocalizationManager.Instance;
var nameLabel = new Label();
nameLabel.Text = loc.GetText("save_dialog_enter_name");
vbox.AddChild(nameLabel);
_nameInput = new LineEdit();
_nameInput.PlaceholderText = loc.GetText("save_dialog_placeholder");
_nameInput.Text = $"Save {System.DateTime.Now:HH:mm:ss}";
vbox.AddChild(_nameInput);
AddChild(vbox);
// Visa OK-knappen igen och anslut till ny save
GetOkButton().Visible = true;
// Ta bort tidigare signaler och lägg till ny
if (IsConnected("confirmed", new Callable(this, nameof(OnSaveConfirmed))))
{
Disconnect("confirmed", new Callable(this, nameof(OnSaveConfirmed)));
}
Confirmed += OnNewSaveConfirmed;
// Fokusera på text input
_nameInput.GrabFocus();
_nameInput.SelectAll();
}
private void OnNewSaveConfirmed()
{
if (_gameController != null)
{
string saveName = _nameInput.Text.Trim();
if (string.IsNullOrEmpty(saveName))
{
saveName = $"Save {System.DateTime.Now:HH:mm:ss}";
}
var saveManager = new SaveManager();
float currentTime = _gameController.GetGameTime();
bool saveSuccess = saveManager.SaveGame(currentTime, saveName, GameState.CurrentGameSeed, false); // overwriteLatest = false (ny instans)
if (saveSuccess)
{
GameState.MarkProgressAsSaved(currentTime);
_gameController.TogglePause();
}
else
{
ShowErrorDialog("Failed to save the game. Please try again.");
return;
}
}
QueueFree();
}
private void OnSaveConfirmed()
{
// För första gången man sparar
if (_gameController != null)
{
string saveName = _nameInput.Text.Trim();
if (string.IsNullOrEmpty(saveName))
{
saveName = $"Save {System.DateTime.Now:HH:mm:ss}";
}
var saveManager = new SaveManager();
float currentTime = _gameController.GetGameTime();
bool saveSuccess = saveManager.SaveGame(currentTime, saveName, GameState.CurrentGameSeed, false); // Första save är alltid ny instans
if (saveSuccess)
{
GameState.MarkProgressAsSaved(currentTime);
_gameController.TogglePause();
}
else
{
ShowErrorDialog("Failed to save the game. Please try again.");
return;
}
}
QueueFree();
}
private void SetProcessModeRecursive(Node node, ProcessModeEnum mode)
{
if (node is Control control)
{
control.ProcessMode = mode;
}
foreach (Node child in node.GetChildren())
{
SetProcessModeRecursive(child, mode);
}
}
public override void _Input(InputEvent @event)
{
if (@event is InputEventKey keyEvent && keyEvent.Pressed)
{
if (keyEvent.Keycode == Key.Enter || keyEvent.Keycode == Key.KpEnter)
{
// Hantera Enter baserat på nuvarande state
if (_nameInput != null && _nameInput.Visible)
{
if (IsConnected("confirmed", new Callable(this, nameof(OnNewSaveConfirmed))))
{
OnNewSaveConfirmed();
}
else
{
OnSaveConfirmed();
}
}
GetViewport().SetInputAsHandled();
}
else if (keyEvent.Keycode == Key.Escape)
{
Hide();
QueueFree();
GetViewport().SetInputAsHandled();
}
}
}
private void FocusNameInput()
{
if (_nameInput != null && IsInsideTree())
{
_nameInput.GrabFocus();
_nameInput.SelectAll();
}
}
}
}

View File

@@ -0,0 +1 @@
uid://bbvu2wk22cfb3

View File

@@ -0,0 +1,106 @@
using Godot;
using System;
namespace TheGame
{
public partial class ExitConfirmationDialog : AcceptDialog
{
private Action _onConfirm;
private Button _yesButton;
private Button _noButton;
private Label _messageLabel;
public override void _Ready()
{
// Lägg till i localized_ui gruppen
AddToGroup("localized_ui");
// Skapa dialog layout
SetupDialog();
UpdateLocalization();
}
private void SetupDialog()
{
// Sätt dialog egenskaper
Title = "";
Unresizable = false;
ProcessMode = ProcessModeEnum.WhenPaused;
// Ta bort standard OK knapp
GetOkButton().QueueFree();
// Skapa innehåll
var vbox = new VBoxContainer();
AddChild(vbox);
_messageLabel = new Label();
_messageLabel.HorizontalAlignment = HorizontalAlignment.Center;
_messageLabel.AutowrapMode = TextServer.AutowrapMode.WordSmart;
vbox.AddChild(_messageLabel);
// Lägg till mellanrum
var spacer = new Control();
spacer.CustomMinimumSize = new Vector2(0, 20);
vbox.AddChild(spacer);
// Skapa knappar
var buttonContainer = new HBoxContainer();
buttonContainer.Alignment = BoxContainer.AlignmentMode.Center;
vbox.AddChild(buttonContainer);
_yesButton = new Button();
_yesButton.Pressed += OnYesPressed;
buttonContainer.AddChild(_yesButton);
// Lägg till mellanrum mellan knappar
var buttonSpacer = new Control();
buttonSpacer.CustomMinimumSize = new Vector2(20, 0);
buttonContainer.AddChild(buttonSpacer);
_noButton = new Button();
_noButton.Pressed += OnNoPressed;
buttonContainer.AddChild(_noButton);
// Sätt minimum storlek för dialog
Size = new Vector2I(400, 200);
}
public void UpdateLocalization()
{
var loc = LocalizationManager.Instance;
Title = loc.GetText("exit_warning_title");
_messageLabel.Text = loc.GetText("exit_warning_message");
_yesButton.Text = loc.GetText("yes");
_noButton.Text = loc.GetText("no");
}
public void ShowDialog(Action onConfirm)
{
_onConfirm = onConfirm;
PopupCentered();
_noButton.GrabFocus(); // Fokusera på "Nej" som säkrare alternativ
}
private void OnYesPressed()
{
Hide();
_onConfirm?.Invoke();
}
private void OnNoPressed()
{
Hide();
}
public override void _Input(InputEvent @event)
{
// Hantera ESC för att stänga dialog (samma som "Nej")
if (@event.IsActionPressed("ui_cancel") && Visible)
{
OnNoPressed();
GetViewport().SetInputAsHandled();
}
}
}
}

View File

@@ -0,0 +1 @@
uid://ca1pkqrwj3k4p

View File

@@ -0,0 +1,101 @@
using Godot;
namespace TheGame
{
public partial class SaveDialog : AcceptDialog
{
private LineEdit _nameInput;
private Game _gameController;
public override void _Ready()
{
// Sätt process mode så att dialogen fungerar när spelet är pausat
ProcessMode = ProcessModeEnum.WhenPaused;
var loc = LocalizationManager.Instance;
Title = loc.GetText("save_dialog_title");
// Skapa innehåll för dialogen
var vbox = new VBoxContainer();
var label = new Label();
label.Text = loc.GetText("save_dialog_enter_name");
vbox.AddChild(label);
_nameInput = new LineEdit();
_nameInput.PlaceholderText = loc.GetText("save_dialog_placeholder");
_nameInput.Text = $"Save {System.DateTime.Now:yyyy-MM-dd HH:mm}";
vbox.AddChild(_nameInput);
AddChild(vbox);
// Sätt process mode på alla child nodes
SetProcessModeRecursive(this, ProcessModeEnum.WhenPaused);
// Anslut signaler
Confirmed += OnSaveConfirmed;
// Fokusera på text input
_nameInput.GrabFocus();
_nameInput.SelectAll();
}
public void Initialize(Game gameController)
{
_gameController = gameController;
}
private void OnSaveConfirmed()
{
if (_gameController != null)
{
string saveName = _nameInput.Text.Trim();
if (string.IsNullOrEmpty(saveName))
{
saveName = $"Save {System.DateTime.Now:yyyy-MM-dd HH:mm}";
}
var saveManager = new SaveManager();
float currentTime = _gameController.GetGameTime();
saveManager.SaveGame(currentTime, saveName);
// Stäng pausmenyn och återgå till spelet
_gameController.TogglePause();
}
QueueFree();
}
private void SetProcessModeRecursive(Node node, ProcessModeEnum mode)
{
if (node is Control control)
{
control.ProcessMode = mode;
}
foreach (Node child in node.GetChildren())
{
SetProcessModeRecursive(child, mode);
}
}
public override void _Input(InputEvent @event)
{
// Se till att input fungerar när spelet är pausat
if (@event is InputEventKey keyEvent && keyEvent.Pressed)
{
if (keyEvent.Keycode == Key.Enter || keyEvent.Keycode == Key.KpEnter)
{
OnSaveConfirmed();
GetViewport().SetInputAsHandled();
}
else if (keyEvent.Keycode == Key.Escape)
{
Hide();
QueueFree();
GetViewport().SetInputAsHandled();
}
}
}
}
}

View File

@@ -0,0 +1 @@
uid://fda254rf83ot

View File

@@ -0,0 +1,121 @@
using Godot;
using System.Collections.Generic;
using System.Linq;
namespace TheGame
{
public partial class InstanceSelectionMenu : AcceptDialog
{
private SaveData _saveData;
private VBoxContainer _instanceList;
private Button _cancelButton;
public override void _Ready()
{
ProcessMode = ProcessModeEnum.Always;
Title = "Select Save Instance";
var vbox = new VBoxContainer();
// Header info
var headerLabel = new Label();
headerLabel.Text = $"Game Seed: {_saveData?.GameSeed?.ToString() ?? "Unknown"}";
headerLabel.AddThemeStyleboxOverride("normal", new StyleBoxFlat());
vbox.AddChild(headerLabel);
var separator = new HSeparator();
vbox.AddChild(separator);
// Scroll container för instanser
var scrollContainer = new ScrollContainer();
scrollContainer.CustomMinimumSize = new Vector2(0, 300);
_instanceList = new VBoxContainer();
scrollContainer.AddChild(_instanceList);
vbox.AddChild(scrollContainer);
// Cancel button
var buttonContainer = new HBoxContainer();
buttonContainer.Alignment = BoxContainer.AlignmentMode.End;
_cancelButton = new Button();
_cancelButton.Text = "Cancel";
_cancelButton.Pressed += OnCancelPressed;
buttonContainer.AddChild(_cancelButton);
vbox.AddChild(buttonContainer);
AddChild(vbox);
PopulateInstanceList();
}
public void Initialize(SaveData saveData)
{
_saveData = saveData;
}
private void PopulateInstanceList()
{
if (_saveData?.Instances == null) return;
// Sortera instances efter save date (nyast först)
var sortedInstances = _saveData.Instances.OrderByDescending(i => i.SaveDate).ToList();
foreach (var instance in sortedInstances)
{
var instanceButton = new Button();
instanceButton.CustomMinimumSize = new Vector2(0, 60);
instanceButton.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
// Skapa text med formatering
var instanceText = $"{instance.DisplayName}\n";
instanceText += $"Game Time: {instance.GetFormattedGameTime()}\n";
instanceText += $"Saved: {instance.SaveDate:yyyy-MM-dd HH:mm:ss}";
instanceButton.Text = instanceText;
instanceButton.Pressed += () => OnInstanceSelected(instance);
_instanceList.AddChild(instanceButton);
}
}
private void OnInstanceSelected(SaveInstance instance)
{
var saveManager = new SaveManager();
if (saveManager.LoadGame(_saveData, instance))
{
GetTree().ChangeSceneToFile("res://scenes/Game.tscn");
}
else
{
GD.PrintErr("Failed to load selected game instance");
// Visa error message till användaren
var errorDialog = new AcceptDialog();
errorDialog.DialogText = "Failed to load the selected save instance.";
errorDialog.Title = "Load Error";
GetTree().Root.AddChild(errorDialog);
errorDialog.PopupCentered();
}
QueueFree();
}
private void OnCancelPressed()
{
QueueFree();
}
public override void _Input(InputEvent @event)
{
if (@event is InputEventKey keyEvent && keyEvent.Pressed)
{
if (keyEvent.Keycode == Key.Escape)
{
OnCancelPressed();
GetViewport().SetInputAsHandled();
}
}
}
}
}

View File

@@ -0,0 +1 @@
uid://clbtayqmos4qt

View File

@@ -0,0 +1,133 @@
using Godot;
using System.Collections.Generic;
namespace TheGame
{
public partial class LoadGameMenu : Control
{
private VBoxContainer _saveList;
private SaveManager _saveManager;
private Label _titleLabel;
private Button _backButton;
public override void _Ready()
{
// Lägg till i localized_ui gruppen
AddToGroup("localized_ui");
_saveList = GetNode<VBoxContainer>("VBoxContainer/ScrollContainer/SaveList");
_titleLabel = GetNode<Label>("VBoxContainer/TitleLabel");
_backButton = GetNode<Button>("VBoxContainer/BackButton");
_saveManager = new SaveManager();
UpdateLocalization();
PopulateSaveList();
}
public void UpdateLocalization()
{
var loc = LocalizationManager.Instance;
_titleLabel.Text = loc.GetText("load_game_title");
_backButton.Text = loc.GetText("load_game_back");
}
public override void _Notification(int what)
{
if (what == NotificationWMCloseRequest)
{
// I load game menyn kan vi avsluta direkt
GetTree().Quit();
}
}
private void PopulateSaveList()
{
// Rensa tidigare innehåll
foreach (Node child in _saveList.GetChildren())
{
child.QueueFree();
}
var savedGames = _saveManager.GetSavedGames();
if (savedGames.Count == 0)
{
var noSavesLabel = new Label();
var loc = LocalizationManager.Instance;
noSavesLabel.Text = loc.GetText("load_game_no_saves");
noSavesLabel.HorizontalAlignment = HorizontalAlignment.Center;
_saveList.AddChild(noSavesLabel);
return;
}
foreach (var saveData in savedGames)
{
var gameContainer = new VBoxContainer();
gameContainer.AddThemeConstantOverride("separation", 5);
// Header med seed info
var seedLabel = new Label();
seedLabel.Text = $"Game: {saveData.GameSeed.ToString()}";
seedLabel.AddThemeStyleboxOverride("normal", new StyleBoxFlat());
gameContainer.AddChild(seedLabel);
// Continue button (senaste instansen)
var latestInstance = saveData.GetLatestInstance();
if (latestInstance != null)
{
var continueButton = new Button();
continueButton.Text = $"Continue: {latestInstance.DisplayName}\nTime: {latestInstance.GetFormattedGameTime()}\nSaved: {latestInstance.SaveDate:yyyy-MM-dd HH:mm}";
continueButton.Pressed += () => LoadGame(saveData, latestInstance);
gameContainer.AddChild(continueButton);
}
// Load Previous button (om det finns fler instanser)
if (saveData.Instances.Count > 1)
{
var loadPreviousButton = new Button();
loadPreviousButton.Text = $"Load Previous ({saveData.Instances.Count - 1} other saves)";
loadPreviousButton.Pressed += () => ShowInstanceSelection(saveData);
gameContainer.AddChild(loadPreviousButton);
}
// Separator mellan games
var separator = new HSeparator();
gameContainer.AddChild(separator);
_saveList.AddChild(gameContainer);
}
}
private void LoadGame(SaveData saveData, SaveInstance instance = null)
{
if (_saveManager.LoadGame(saveData, instance))
{
GetTree().ChangeSceneToFile("res://scenes/Game.tscn");
}
else
{
GD.PrintErr("Failed to load selected game");
// Visa error message
var errorDialog = new AcceptDialog();
errorDialog.DialogText = "Failed to load the selected save.";
errorDialog.Title = "Load Error";
GetTree().Root.AddChild(errorDialog);
errorDialog.PopupCentered();
}
}
private void ShowInstanceSelection(SaveData saveData)
{
var instanceMenu = new InstanceSelectionMenu();
instanceMenu.Initialize(saveData);
GetTree().Root.AddChild(instanceMenu);
instanceMenu.PopupCentered(new Vector2I(500, 400));
}
private void _on_back_button_pressed()
{
GetTree().ChangeSceneToFile("res://scenes/MainMenu.tscn");
}
}
}

View File

@@ -0,0 +1 @@
uid://dt0pqnx0paqkj

View File

@@ -0,0 +1,88 @@
using Godot;
namespace TheGame
{
public partial class MainMenu : Control
{
private Button _loadButton;
private Label _titleLabel;
private Button _startButton;
private Button _settingsButton;
private Button _exitButton;
public override void _Ready()
{
// Lägg till i localized_ui gruppen
AddToGroup("localized_ui");
_loadButton = GetNode<Button>("VBoxContainer/LoadButton");
_titleLabel = GetNode<Label>("VBoxContainer/TitleLabel");
_startButton = GetNode<Button>("VBoxContainer/StartButton");
_settingsButton = GetNode<Button>("VBoxContainer/SettingsButton");
_exitButton = GetNode<Button>("VBoxContainer/ExitButton");
// Initiera inställningar och språk
GameSettings.Instance.ApplyAllSettings();
UpdateLoadButtonState();
UpdateLocalization();
}
public void UpdateLocalization()
{
var loc = LocalizationManager.Instance;
_titleLabel.Text = loc.GetText("main_menu_title");
_startButton.Text = loc.GetText("main_menu_start");
_loadButton.Text = loc.GetText("main_menu_load");
_settingsButton.Text = loc.GetText("main_menu_settings");
_exitButton.Text = loc.GetText("main_menu_exit");
}
private void UpdateLoadButtonState()
{
// Kontrollera om det finns sparade spel
var saveManager = new SaveManager();
var savedGames = saveManager.GetSavedGames();
_loadButton.Disabled = savedGames.Count == 0;
}
private void _on_start_button_pressed()
{
// Rensa befintligt game state för att starta nytt spel
GameState.ResetGameState();
GetTree().ChangeSceneToFile("res://scenes/Game.tscn");
}
public override void _Notification(int what)
{
if (what == NotificationWMCloseRequest)
{
// I huvudmenyn kan vi avsluta direkt
GetTree().Quit();
}
}
private void _on_load_button_pressed()
{
GetTree().ChangeSceneToFile("res://scenes/LoadGameMenu.tscn");
}
private void _on_settings_button_pressed()
{
// Skapa settings menu som popup
var settingsScene = GD.Load<PackedScene>("res://scenes/SettingsMenu.tscn");
var settingsMenu = settingsScene.Instantiate<SettingsMenu>();
// Sätt process mode för main menu context
settingsMenu.ProcessMode = ProcessModeEnum.Always;
GetTree().Root.AddChild(settingsMenu);
}
private void _on_exit_button_pressed()
{
GetTree().Quit();
}
}
}

View File

@@ -0,0 +1 @@
uid://cq88pp73k3b4

View File

@@ -0,0 +1,84 @@
using Godot;
namespace TheGame
{
public partial class PauseMenu : Control
{
private Game _gameController;
private Label _titleLabel;
private Button _resumeButton;
private Button _saveButton;
private Button _settingsButton;
private Button _mainMenuButton;
private Button _desktopButton;
public override void _Ready()
{
// Lägg till i localized_ui gruppen
AddToGroup("localized_ui");
_gameController = GetParent<Game>();
_titleLabel = GetNode<Label>("MenuContainer/TitleLabel");
_resumeButton = GetNode<Button>("MenuContainer/ResumeButton");
_saveButton = GetNode<Button>("MenuContainer/SaveButton");
_settingsButton = GetNode<Button>("MenuContainer/SettingsButton");
_mainMenuButton = GetNode<Button>("MenuContainer/MainMenuButton");
_desktopButton = GetNode<Button>("MenuContainer/DesktopButton");
UpdateLocalization();
}
public void UpdateLocalization()
{
var loc = LocalizationManager.Instance;
_titleLabel.Text = loc.GetText("pause_menu_title");
_resumeButton.Text = loc.GetText("pause_menu_resume");
_saveButton.Text = loc.GetText("pause_menu_save");
_settingsButton.Text = loc.GetText("pause_menu_settings");
_mainMenuButton.Text = loc.GetText("pause_menu_main_menu");
_desktopButton.Text = loc.GetText("pause_menu_desktop");
}
private void _on_resume_button_pressed()
{
_gameController.TogglePause();
}
private void _on_save_button_pressed()
{
// Skapa och visa advanced save dialog
var advancedSaveDialog = new AdvancedSaveDialog();
advancedSaveDialog.ProcessMode = ProcessModeEnum.WhenPaused; // Sätt innan initialize
advancedSaveDialog.Initialize(_gameController);
GetTree().Root.AddChild(advancedSaveDialog);
advancedSaveDialog.PopupCentered(new Vector2I(450, 350));
}
private void _on_settings_button_pressed()
{
// Skapa settings menu som popup
var settingsScene = GD.Load<PackedScene>("res://scenes/SettingsMenu.tscn");
var settingsMenu = settingsScene.Instantiate<SettingsMenu>();
// Sätt process mode så att den fungerar när pausat
settingsMenu.ProcessMode = ProcessModeEnum.WhenPaused;
GetTree().Root.AddChild(settingsMenu);
}
private void _on_main_menu_button_pressed()
{
_gameController.HandleExitRequest(() => {
GetTree().Paused = false;
GameState.ResetGameState();
GetTree().ChangeSceneToFile("res://scenes/MainMenu.tscn");
});
}
private void _on_desktop_button_pressed()
{
_gameController.HandleExitRequest(() => GetTree().Quit());
}
}
}

View File

@@ -0,0 +1 @@
uid://cre1pwcc5y5u3

View File

@@ -0,0 +1,288 @@
using Godot;
using System.Collections.Generic;
namespace TheGame
{
public partial class SettingsMenu : Control
{
// UI References
private Label _titleLabel;
private TabContainer _tabContainer;
// General Tab
private Label _languageLabel;
private OptionButton _languageOption;
// Video Tab
private Label _fullscreenLabel;
private CheckBox _fullscreenCheck;
// Audio Tab
private Label _masterLabel;
private HSlider _masterSlider;
private Label _backgroundLabel;
private HSlider _backgroundSlider;
private Label _effectsLabel;
private HSlider _effectsSlider;
private Label _radioLabel;
private HSlider _radioSlider;
// Buttons
private Button _applyButton;
private Button _cancelButton;
private Button _backButton;
// Settings
private GameSettings _settings;
private GameSettings _originalSettings;
public override void _Ready()
{
// Lägg till i localized_ui gruppen för språkuppdateringar
AddToGroup("localized_ui");
// Sätt process mode baserat på om spelet är pausat eller inte
if (GetTree().Paused)
{
ProcessMode = ProcessModeEnum.WhenPaused;
}
else
{
ProcessMode = ProcessModeEnum.Always;
}
// Hämta UI referenser
GetUIReferences();
// Ladda nuvarande inställningar
_settings = GameSettings.Instance;
_originalSettings = new GameSettings
{
Fullscreen = _settings.Fullscreen,
MasterVolume = _settings.MasterVolume,
BackgroundVolume = _settings.BackgroundVolume,
EffectsVolume = _settings.EffectsVolume,
RadioVolume = _settings.RadioVolume,
Language = _settings.Language
};
// Sätt process mode på alla UI element så de fungerar när pausat
SetProcessModeRecursive(this, ProcessModeEnum.WhenPaused);
// Initiera UI
InitializeLanguageOptions();
LoadCurrentSettings();
UpdateLocalization();
}
public override void _Notification(int what)
{
if (what == NotificationWMCloseRequest)
{
// Settings menyn är en popup, så vi stänger bara den själv
_on_cancel_button_pressed();
}
}
private void SetProcessModeRecursive(Node node, ProcessModeEnum mode)
{
if (node is Control control)
{
control.ProcessMode = mode;
}
foreach (Node child in node.GetChildren())
{
SetProcessModeRecursive(child, mode);
}
}
private void GetUIReferences()
{
_titleLabel = GetNode<Label>("MainContainer/TitleLabel");
_tabContainer = GetNode<TabContainer>("MainContainer/TabContainer");
// General
_languageLabel = GetNode<Label>("MainContainer/TabContainer/General/GeneralVBox/LanguageContainer/LanguageLabel");
_languageOption = GetNode<OptionButton>("MainContainer/TabContainer/General/GeneralVBox/LanguageContainer/LanguageOption");
// Video
_fullscreenLabel = GetNode<Label>("MainContainer/TabContainer/Video/VideoVBox/FullscreenContainer/FullscreenLabel");
_fullscreenCheck = GetNode<CheckBox>("MainContainer/TabContainer/Video/VideoVBox/FullscreenContainer/FullscreenCheck");
// Audio
_masterLabel = GetNode<Label>("MainContainer/TabContainer/Audio/AudioVBox/MasterContainer/MasterLabel");
_masterSlider = GetNode<HSlider>("MainContainer/TabContainer/Audio/AudioVBox/MasterContainer/MasterSlider");
_backgroundLabel = GetNode<Label>("MainContainer/TabContainer/Audio/AudioVBox/BackgroundContainer/BackgroundLabel");
_backgroundSlider = GetNode<HSlider>("MainContainer/TabContainer/Audio/AudioVBox/BackgroundContainer/BackgroundSlider");
_effectsLabel = GetNode<Label>("MainContainer/TabContainer/Audio/AudioVBox/EffectsContainer/EffectsLabel");
_effectsSlider = GetNode<HSlider>("MainContainer/TabContainer/Audio/AudioVBox/EffectsContainer/EffectsSlider");
_radioLabel = GetNode<Label>("MainContainer/TabContainer/Audio/AudioVBox/RadioContainer/RadioLabel");
_radioSlider = GetNode<HSlider>("MainContainer/TabContainer/Audio/AudioVBox/RadioContainer/RadioSlider");
// Buttons
_applyButton = GetNode<Button>("MainContainer/ButtonContainer/ApplyButton");
_cancelButton = GetNode<Button>("MainContainer/ButtonContainer/CancelButton");
_backButton = GetNode<Button>("MainContainer/ButtonContainer/BackButton");
}
private void InitializeLanguageOptions()
{
_languageOption.Clear();
var availableLanguages = LocalizationManager.Instance.GetAvailableLanguages();
var languageNames = new Dictionary<string, string>
{
{"eng", "English"},
{"sve", "Svenska"}
};
foreach (string lang in availableLanguages)
{
string displayName = languageNames.ContainsKey(lang) ? languageNames[lang] : lang.ToUpper();
_languageOption.AddItem(displayName);
_languageOption.SetItemMetadata(_languageOption.GetItemCount() - 1, lang);
}
}
private void LoadCurrentSettings()
{
// Language
for (int i = 0; i < _languageOption.GetItemCount(); i++)
{
if (_languageOption.GetItemMetadata(i).AsString() == _settings.Language)
{
_languageOption.Selected = i;
break;
}
}
// Video
_fullscreenCheck.ButtonPressed = _settings.Fullscreen;
// Audio
_masterSlider.Value = _settings.MasterVolume;
_backgroundSlider.Value = _settings.BackgroundVolume;
_effectsSlider.Value = _settings.EffectsVolume;
_radioSlider.Value = _settings.RadioVolume;
UpdateVolumeLabels();
}
private void UpdateVolumeLabels()
{
var loc = LocalizationManager.Instance;
_masterLabel.Text = $"{loc.GetText("settings_master_volume")}: {(int)_masterSlider.Value}";
_backgroundLabel.Text = $"{loc.GetText("settings_background_volume")}: {(int)_backgroundSlider.Value}";
_effectsLabel.Text = $"{loc.GetText("settings_effects_volume")}: {(int)_effectsSlider.Value}";
_radioLabel.Text = $"{loc.GetText("settings_radio_volume")}: {(int)_radioSlider.Value}";
}
public void UpdateLocalization()
{
var loc = LocalizationManager.Instance;
_titleLabel.Text = loc.GetText("settings_title");
// Tab names
_tabContainer.SetTabTitle(0, loc.GetText("settings_general"));
_tabContainer.SetTabTitle(1, loc.GetText("settings_video"));
_tabContainer.SetTabTitle(2, loc.GetText("settings_audio"));
// General
_languageLabel.Text = loc.GetText("settings_language") + ":";
// Video
_fullscreenLabel.Text = loc.GetText("settings_fullscreen") + ":";
// Audio
UpdateVolumeLabels();
// Buttons
_applyButton.Text = loc.GetText("settings_apply");
_cancelButton.Text = loc.GetText("settings_cancel");
_backButton.Text = loc.GetText("settings_back");
}
// Signal handlers
private void _on_language_option_item_selected(int index)
{
string selectedLanguage = _languageOption.GetItemMetadata(index).AsString();
_settings.Language = selectedLanguage;
// Tillämpa språkändring direkt
LocalizationManager.Instance.SetLanguage(selectedLanguage);
}
private void _on_fullscreen_check_toggled(bool buttonPressed)
{
_settings.Fullscreen = buttonPressed;
}
private void _on_master_slider_value_changed(double value)
{
_settings.MasterVolume = (int)value;
UpdateVolumeLabels();
}
private void _on_background_slider_value_changed(double value)
{
_settings.BackgroundVolume = (int)value;
UpdateVolumeLabels();
}
private void _on_effects_slider_value_changed(double value)
{
_settings.EffectsVolume = (int)value;
UpdateVolumeLabels();
}
private void _on_radio_slider_value_changed(double value)
{
_settings.RadioVolume = (int)value;
UpdateVolumeLabels();
}
private void _on_apply_button_pressed()
{
_settings.ApplyAllSettings();
GoBack();
}
private void _on_cancel_button_pressed()
{
// Återställ inställningar
_settings.Fullscreen = _originalSettings.Fullscreen;
_settings.MasterVolume = _originalSettings.MasterVolume;
_settings.BackgroundVolume = _originalSettings.BackgroundVolume;
_settings.EffectsVolume = _originalSettings.EffectsVolume;
_settings.RadioVolume = _originalSettings.RadioVolume;
_settings.Language = _originalSettings.Language;
// Återställ språk
LocalizationManager.Instance.SetLanguage(_originalSettings.Language);
GoBack();
}
private void _on_back_button_pressed()
{
_on_apply_button_pressed(); // Spara ändringar när man går tillbaka
}
private void GoBack()
{
// Kontrollera varifrån vi kom
if (GetTree().Paused)
{
// Vi kom från pausmenyn - ta bara bort settings window
QueueFree();
}
else
{
// Vi kom från huvudmenyn
GetTree().ChangeSceneToFile("res://scenes/MainMenu.tscn");
}
}
}
}

View File

@@ -0,0 +1 @@
uid://di6gyor6n6lje