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:
143
scripts/Core/Game.cs
Normal file
143
scripts/Core/Game.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using Godot;
|
||||
|
||||
namespace TheGame
|
||||
{
|
||||
public partial class Game : Control
|
||||
{
|
||||
private Label _timerLabel;
|
||||
private Control _pauseMenu;
|
||||
private Label _gameContentLabel;
|
||||
private float _gameTime = 0.0f;
|
||||
private bool _isPaused = false;
|
||||
private ExitConfirmationDialog _exitDialog;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
// Lägg till i localized_ui gruppen
|
||||
AddToGroup("localized_ui");
|
||||
|
||||
_timerLabel = GetNode<Label>("UI/TimerLabel");
|
||||
_pauseMenu = GetNode<Control>("PauseMenu");
|
||||
_gameContentLabel = GetNode<Label>("GameContent");
|
||||
|
||||
// Sätt process mode så att pausmenyn fungerar när spelet är pausat
|
||||
_pauseMenu.ProcessMode = ProcessModeEnum.WhenPaused;
|
||||
|
||||
// Kontrollera om vi laddar ett sparat spel eller startar nytt
|
||||
if (GameState.LoadedGameTime >= 0)
|
||||
{
|
||||
// Laddar befintligt spel
|
||||
_gameTime = GameState.LoadedGameTime;
|
||||
GameState.LastSavedGameTime = _gameTime; // Sätt senaste sparade tid
|
||||
GameState.LoadedGameTime = -1; // Reset efter användning
|
||||
GD.Print($"Loaded existing game with seed: {GameState.CurrentGameSeed?.ToString() ?? "None"}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nytt spel - skapa ny seed om ingen finns
|
||||
if (GameState.CurrentGameSeed == null)
|
||||
{
|
||||
GameState.CurrentGameSeed = new GameSeed();
|
||||
GD.Print($"Started new game with seed: {GameState.CurrentGameSeed.ToString()}");
|
||||
}
|
||||
GameState.LastSavedGameTime = 0;
|
||||
}
|
||||
|
||||
// Skapa exit confirmation dialog
|
||||
_exitDialog = new ExitConfirmationDialog();
|
||||
AddChild(_exitDialog);
|
||||
|
||||
// Hantera fönsterstängning
|
||||
GetTree().AutoAcceptQuit = false;
|
||||
|
||||
UpdateLocalization();
|
||||
}
|
||||
|
||||
public void UpdateLocalization()
|
||||
{
|
||||
var loc = LocalizationManager.Instance;
|
||||
_gameContentLabel.Text = loc.GetText("game_content");
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
if (!_isPaused)
|
||||
{
|
||||
_gameTime += (float)delta;
|
||||
UpdateTimerDisplay();
|
||||
|
||||
// Kontrollera om det finns osparad progress
|
||||
GameState.CheckUnsavedProgress(_gameTime);
|
||||
}
|
||||
}
|
||||
|
||||
public override void _Notification(int what)
|
||||
{
|
||||
if (what == NotificationWMCloseRequest)
|
||||
{
|
||||
// Hantera X-knappen på fönstret
|
||||
HandleExitRequest(() => GetTree().Quit());
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleExitRequest(System.Action exitAction)
|
||||
{
|
||||
if (GameState.HasUnsavedProgress)
|
||||
{
|
||||
// Pausa spelet och visa varning
|
||||
if (!_isPaused)
|
||||
{
|
||||
TogglePause();
|
||||
}
|
||||
_exitDialog.ShowDialog(exitAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ingen osparad progress, avsluta direkt
|
||||
exitAction?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
if (@event.IsActionPressed("ui_cancel")) // ESC key
|
||||
{
|
||||
TogglePause();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTimerDisplay()
|
||||
{
|
||||
int hours = (int)(_gameTime / 3600);
|
||||
int minutes = (int)((_gameTime % 3600) / 60);
|
||||
int seconds = (int)(_gameTime % 60);
|
||||
|
||||
_timerLabel.Text = $"{hours:D2}:{minutes:D2}:{seconds:D2}";
|
||||
}
|
||||
|
||||
public void TogglePause()
|
||||
{
|
||||
_isPaused = !_isPaused;
|
||||
_pauseMenu.Visible = _isPaused;
|
||||
|
||||
if (_isPaused)
|
||||
{
|
||||
GetTree().Paused = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
GetTree().Paused = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void _on_pause_button_pressed()
|
||||
{
|
||||
TogglePause();
|
||||
}
|
||||
|
||||
public float GetGameTime()
|
||||
{
|
||||
return _gameTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
1
scripts/Core/Game.cs.uid
Normal file
1
scripts/Core/Game.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b58rkdlq5w21m
|
||||
148
scripts/Core/GameSettings.cs
Normal file
148
scripts/Core/GameSettings.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace TheGame
|
||||
{
|
||||
public class GameSettings
|
||||
{
|
||||
public bool Fullscreen { get; set; } = false;
|
||||
public int MasterVolume { get; set; } = 100;
|
||||
public int BackgroundVolume { get; set; } = 100;
|
||||
public int EffectsVolume { get; set; } = 100;
|
||||
public int RadioVolume { get; set; } = 100;
|
||||
public string Language { get; set; } = "eng";
|
||||
|
||||
private static GameSettings _instance;
|
||||
private static readonly string _settingsPath;
|
||||
|
||||
static GameSettings()
|
||||
{
|
||||
// Spara bredvid binären (executable directory)
|
||||
string executableDir = OS.GetExecutablePath().GetBaseDir();
|
||||
_settingsPath = Path.Combine(executableDir, "settings.json");
|
||||
}
|
||||
|
||||
public static GameSettings Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = LoadSettings();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private static GameSettings LoadSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(_settingsPath))
|
||||
{
|
||||
string jsonString = File.ReadAllText(_settingsPath);
|
||||
var settings = JsonSerializer.Deserialize<GameSettings>(jsonString);
|
||||
if (settings != null)
|
||||
{
|
||||
GD.Print($"Settings loaded from: {_settingsPath}");
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GD.PrintErr($"Failed to load settings: {ex.Message}");
|
||||
}
|
||||
|
||||
// Returnera standardinställningar om fil inte finns eller laddning misslyckas
|
||||
GD.Print("Using default settings");
|
||||
return new GameSettings();
|
||||
}
|
||||
|
||||
public void SaveSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(this, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
});
|
||||
File.WriteAllText(_settingsPath, jsonString);
|
||||
GD.Print($"Settings saved to: {_settingsPath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GD.PrintErr($"Failed to save settings: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyVideoSettings()
|
||||
{
|
||||
if (Fullscreen)
|
||||
{
|
||||
DisplayServer.WindowSetMode(DisplayServer.WindowMode.Fullscreen);
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayServer.WindowSetMode(DisplayServer.WindowMode.Windowed);
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyAudioSettings()
|
||||
{
|
||||
// Konvertera från 1-100 till dB (Godot använder dB för ljud)
|
||||
float masterDb = ConvertVolumeToDb(MasterVolume);
|
||||
float backgroundDb = ConvertVolumeToDb(BackgroundVolume);
|
||||
float effectsDb = ConvertVolumeToDb(EffectsVolume);
|
||||
float radioDb = ConvertVolumeToDb(RadioVolume);
|
||||
|
||||
// Sätt bus-volym (dessa måste skapas i Audio Bus Layout)
|
||||
try
|
||||
{
|
||||
AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("Master"), masterDb);
|
||||
|
||||
int backgroundIndex = AudioServer.GetBusIndex("Background");
|
||||
if (backgroundIndex != -1)
|
||||
AudioServer.SetBusVolumeDb(backgroundIndex, backgroundDb);
|
||||
|
||||
int effectsIndex = AudioServer.GetBusIndex("Effects");
|
||||
if (effectsIndex != -1)
|
||||
AudioServer.SetBusVolumeDb(effectsIndex, effectsDb);
|
||||
|
||||
int radioIndex = AudioServer.GetBusIndex("Radio");
|
||||
if (radioIndex != -1)
|
||||
AudioServer.SetBusVolumeDb(radioIndex, radioDb);
|
||||
|
||||
GD.Print($"Applied audio settings: Master={MasterVolume}, Background={BackgroundVolume}, Effects={EffectsVolume}, Radio={RadioVolume}");
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
GD.PrintErr($"Failed to apply audio settings: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private float ConvertVolumeToDb(int volume)
|
||||
{
|
||||
if (volume <= 0)
|
||||
return -80.0f; // Tyst
|
||||
|
||||
// Konvertera 1-100 till -60dB till 0dB
|
||||
return -60.0f + (volume / 100.0f) * 60.0f;
|
||||
}
|
||||
|
||||
public void ApplyLanguageSettings()
|
||||
{
|
||||
LocalizationManager.Instance.SetLanguage(Language);
|
||||
}
|
||||
|
||||
public void ApplyAllSettings()
|
||||
{
|
||||
ApplyVideoSettings();
|
||||
ApplyAudioSettings();
|
||||
ApplyLanguageSettings();
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
1
scripts/Core/GameSettings.cs.uid
Normal file
1
scripts/Core/GameSettings.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c3t2rdrect1lw
|
||||
37
scripts/Core/GameState.cs
Normal file
37
scripts/Core/GameState.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Godot;
|
||||
|
||||
namespace TheGame
|
||||
{
|
||||
public static class GameState
|
||||
{
|
||||
public static float LoadedGameTime = -1;
|
||||
public static GameSeed CurrentGameSeed = null;
|
||||
public static SaveInstance LoadedInstance = null;
|
||||
public static bool HasUnsavedProgress = false;
|
||||
public static float LastSavedGameTime = 0;
|
||||
|
||||
public static void MarkProgressAsSaved(float gameTime)
|
||||
{
|
||||
LastSavedGameTime = gameTime;
|
||||
HasUnsavedProgress = false;
|
||||
}
|
||||
|
||||
public static void CheckUnsavedProgress(float currentGameTime)
|
||||
{
|
||||
// Om speltiden har ökat sedan senaste sparningen, markera som osparad
|
||||
if (currentGameTime > LastSavedGameTime + 1.0f) // 1 sekund tolerans
|
||||
{
|
||||
HasUnsavedProgress = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ResetGameState()
|
||||
{
|
||||
LoadedGameTime = -1;
|
||||
CurrentGameSeed = null;
|
||||
LoadedInstance = null;
|
||||
HasUnsavedProgress = false;
|
||||
LastSavedGameTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
1
scripts/Core/GameState.cs.uid
Normal file
1
scripts/Core/GameState.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bj2vys8c8nvvg
|
||||
Reference in New Issue
Block a user