Add initial project files and implement core game features

- Created README.md with project description and setup instructions
- Added project configuration files (TheGame.csproj, TheGame.sln, project.godot)
- Implemented main game scenes (MainMenu.tscn, Game.tscn, LoadGameMenu.tscn)
- Developed game logic in C# scripts (Game.cs, MainMenu.cs, LoadGameMenu.cs, PauseMenu.cs, SaveManager.cs)
- Introduced save/load functionality and timer display
- Included icon.svg for game branding
This commit is contained in:
Björn Blomberg
2025-10-16 10:50:04 +02:00
parent b1d835d486
commit 61b03c5801
14 changed files with 767 additions and 1 deletions

129
README.md
View File

@@ -1,3 +1,130 @@
# TheGame
a game about hacking and is a gatcho game
Ett 2D spel byggt i Godot med C# som innehåller en startmeny, timer och save/load funktionalitet.
## Funktioner
- **Startmeny** med knappar för Start Game, Load Game och Exit
- **Timer** som räknar speltid i övre högra hörnet
- **Pausmeny** med knapp i övre vänstra hörnet som innehåller:
- Pause/Resume funktionalitet
- Save Game
- Exit to Main Menu
- Exit to Desktop
- **Save/Load System** som sparar speltid i `saves/` mappen
- **Load Game Menu** som visar alla sparade spel med datum
- Load Game knappen är automatiskt utgråad om inga sparade spel finns
## Krav och Dependencies
### Systemkrav
- **Godot 4.2** eller senare med C# support
- **.NET 6.0** SDK eller senare
- **Windows** (testat på Windows, men bör fungera på andra plattformar)
### Dependencies
Projektet använder följande .NET dependencies:
- `Godot.NET.Sdk` - Godot's .NET SDK
- `System.Text.Json` - För JSON serialisering av sparfiler
## Installation och Setup
### 1. Installera Godot med C# Support
1. Ladda ner Godot 4.2+ **Mono version** från [godotengine.org](https://godotengine.org/download)
2. Installera .NET 6.0 SDK från [Microsoft](https://dotnet.microsoft.com/download)
### 2. Öppna Projektet
1. Starta Godot
2. Klicka på "Import"
3. Navigera till projektmappen och välj `project.godot`
4. Klicka "Import & Edit"
### 3. Första Kompilering
1. I Godot editorn, gå till **Project → Tools → C# → Create C# solution**
2. Vänta tills kompileringen är klar
3. Om fel uppstår, kontrollera att .NET SDK är korrekt installerat
## Kompilering och Körning
### Utvecklingsläge (Godot Editor)
1. Öppna projektet i Godot
2. Tryck **F5** eller klicka på "Play"-knappen
3. Första gången kommer du behöva välja `scenes/MainMenu.tscn` som main scene
### Bygga för Distribution
1. I Godot editorn, gå till **Project → Export**
2. Lägg till en export template för din målplattform (Windows, Linux, macOS)
3. Konfigurera export-inställningar
4. Klicka **Export Project** för att skapa en körbar fil
### Alternativ Kompilering via Terminal
```bash
# Navigera till projektmappen
cd c:\Repo\TheGame
# Bygg projektet
dotnet build
# Kör Godot projekt från kommandoraden (kräver Godot i PATH)
godot --path . scenes/MainMenu.tscn
```
## Projektstruktur
```
TheGame/
├── project.godot # Godot projektfil
├── TheGame.csproj # C# projektfil
├── scenes/ # Godot scener
│ ├── MainMenu.tscn # Huvudmeny
│ ├── Game.tscn # Spelscen
│ └── LoadGameMenu.tscn # Ladda spel meny
├── scripts/ # C# scripts
│ ├── MainMenu.cs # Huvudmeny logik
│ ├── Game.cs # Spel logik och timer
│ ├── PauseMenu.cs # Pausmeny logik
│ ├── SaveManager.cs # Save/Load hantering
│ ├── LoadGameMenu.cs # Ladda spel meny
│ └── GameState.cs # Spelstatus hantering
├── saves/ # Sparade spel (skapas automatiskt)
└── README.md # Denna fil
```
## Kontroller
- **ESC** - Pausa/återuppta spelet
- **Musklick** - Navigera menyer och knappar
- **Pausknapp** (☰) - Pausa spelet (övre vänstra hörnet)
## Felsökning
### Vanliga Problem
1. **"C# script compilation failed"**
- Kontrollera att .NET 6.0 SDK är installerat
- Kör `dotnet --version` i terminal för att verifiera
2. **"Cannot find Godot.NET.Sdk"**
- Se till att du använder Godot Mono version
- Återskapa C# solution via Project → Tools → C# → Create C# solution
3. **Save-filer sparas inte**
- Kontrollera att spelet har skrivrättigheter till projektmappen
- Saves sparas i `saves/` mappen bredvid den körbara filen
4. **Load Game knapp fungerar inte**
- Detta är förväntat beteende om inga sparfiler finns
- Knappen blir automatiskt klickbar när du har sparat minst ett spel
## Utveckling
För att utveckla projektet vidare:
1. Öppna projektet i Godot
2. C# scripts kan redigeras i valfri IDE (Visual Studio, VS Code, Rider)
3. Godot kommer automatiskt att kompilera om scripten när de ändras
4. Använd Godot's debugger för att felsöka runtime-problem
## Licens
Se `LICENSE` filen för licensinformation.

9
TheGame.csproj Normal file
View File

@@ -0,0 +1,9 @@
<Project Sdk="Godot.NET.Sdk/4.2.2">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net7.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'ios' ">net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
<RootNamespace>TheGame</RootNamespace>
</PropertyGroup>
</Project>

24
TheGame.sln Normal file
View File

@@ -0,0 +1,24 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheGame", "TheGame.csproj", "{3104CB95-654D-4767-821F-5F55A5C625DE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3104CB95-654D-4767-821F-5F55A5C625DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3104CB95-654D-4767-821F-5F55A5C625DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3104CB95-654D-4767-821F-5F55A5C625DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3104CB95-654D-4767-821F-5F55A5C625DE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {90CEA6F9-D027-4227-BB50-85F9D2D80783}
EndGlobalSection
EndGlobal

1
icon.svg Normal file
View File

@@ -0,0 +1 @@
<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 191 101 192 3 0 4-5 4-9 0-5-1-9-5-10-1 0-8-15-23-15-6 0-9 7-9 7s6 2 4 3-4 2-4 2-31-77-89-77z"/><path d="m932 600c-3 34-55 191-101 192-3 0-4-5-4-9 0-5 1-9 5-10 1 0 8-15 23-15 6 0 9 7 9 7s-6 2-4 3 4 2 4 2 31-77 89-77z"/><path d="M206 892c0 0 8 18 39 18 13 0 21-8 21-18s-8-18-21-18-39 8-39 18z"/><path d="M1017 892c0 0-8 18-39 18-13 0-21-8-21-18s8-18 21-18 39 8 39 18z"/><path d="M311 1090c0 0 8 18 39 18 13 0 21-8 21-18s-8-18-21-18-39 8-39 18z"/><path d="M1122 1090c0 0-8 18-39 18-13 0-21-8-21-18s8-18 21-18 39 8 39 18z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

30
project.godot Normal file
View File

@@ -0,0 +1,30 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="TheGame"
run/main_scene="res://scenes/MainMenu.tscn"
config/features=PackedStringArray("4.2", "C#", "Forward Plus")
config/icon="res://icon.svg"
[display]
window/size/viewport_width=1280
window/size/viewport_height=720
window/size/resizable=true
[dotnet]
project/assembly_name="TheGame"
[rendering]
renderer/rendering_method="forward_plus"

120
scenes/Game.tscn Normal file
View File

@@ -0,0 +1,120 @@
[gd_scene load_steps=3 format=3 uid="uid://bqkwdpfmu7tge"]
[ext_resource type="Script" path="res://scripts/Game.cs" id="1_xncbp"]
[ext_resource type="Script" path="res://scripts/PauseMenu.cs" id="2_a5qiy"]
[node name="Game" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource("1_xncbp")
[node name="Background" type="ColorRect" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
color = Color(0.2, 0.3, 0.4, 1)
[node name="UI" type="Control" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
[node name="PauseButton" type="Button" parent="UI"]
layout_mode = 0
anchor_right = 0.1
anchor_bottom = 0.08
offset_left = 10.0
offset_top = 10.0
offset_right = -10.0
offset_bottom = -10.0
text = "☰"
[node name="TimerLabel" type="Label" parent="UI"]
layout_mode = 0
anchor_left = 0.85
anchor_right = 1.0
anchor_bottom = 0.08
offset_left = 10.0
offset_top = 10.0
offset_right = -10.0
offset_bottom = -10.0
text = "00:00:00"
horizontal_alignment = 1
vertical_alignment = 1
[node name="GameContent" type="Label" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -100.0
offset_top = -20.0
offset_right = 100.0
offset_bottom = 20.0
text = "GAME CONTENT HERE
Press ESC or click pause button to pause"
horizontal_alignment = 1
vertical_alignment = 1
[node name="PauseMenu" type="Control" parent="."]
visible = false
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource("2_a5qiy")
[node name="Background" type="ColorRect" parent="PauseMenu"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
color = Color(0, 0, 0, 0.8)
[node name="MenuContainer" type="VBoxContainer" parent="PauseMenu"]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -100.0
offset_top = -120.0
offset_right = 100.0
offset_bottom = 120.0
[node name="TitleLabel" type="Label" parent="PauseMenu/MenuContainer"]
layout_mode = 2
text = "PAUSED"
horizontal_alignment = 1
[node name="HSeparator" type="HSeparator" parent="PauseMenu/MenuContainer"]
layout_mode = 2
[node name="ResumeButton" type="Button" parent="PauseMenu/MenuContainer"]
layout_mode = 2
text = "Resume"
[node name="SaveButton" type="Button" parent="PauseMenu/MenuContainer"]
layout_mode = 2
text = "Save Game"
[node name="MainMenuButton" type="Button" parent="PauseMenu/MenuContainer"]
layout_mode = 2
text = "Exit to Main Menu"
[node name="DesktopButton" type="Button" parent="PauseMenu/MenuContainer"]
layout_mode = 2
text = "Exit to Desktop"
[connection signal="pressed" from="UI/PauseButton" to="." method="_on_pause_button_pressed"]
[connection signal="pressed" from="PauseMenu/MenuContainer/ResumeButton" to="PauseMenu" method="_on_resume_button_pressed"]
[connection signal="pressed" from="PauseMenu/MenuContainer/SaveButton" to="PauseMenu" method="_on_save_button_pressed"]
[connection signal="pressed" from="PauseMenu/MenuContainer/MainMenuButton" to="PauseMenu" method="_on_main_menu_button_pressed"]
[connection signal="pressed" from="PauseMenu/MenuContainer/DesktopButton" to="PauseMenu" method="_on_desktop_button_pressed"]

54
scenes/LoadGameMenu.tscn Normal file
View File

@@ -0,0 +1,54 @@
[gd_scene load_steps=2 format=3 uid="uid://cdnyu0lqxhn80"]
[ext_resource type="Script" path="res://scripts/LoadGameMenu.cs" id="1_l8m0c"]
[node name="LoadGameMenu" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource("1_l8m0c")
[node name="Background" type="ColorRect" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
color = Color(0.15, 0.15, 0.25, 1)
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -200.0
offset_top = -200.0
offset_right = 200.0
offset_bottom = 200.0
[node name="TitleLabel" type="Label" parent="VBoxContainer"]
layout_mode = 2
text = "LOAD GAME"
horizontal_alignment = 1
[node name="HSeparator" type="HSeparator" parent="VBoxContainer"]
layout_mode = 2
[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
[node name="SaveList" type="VBoxContainer" parent="VBoxContainer/ScrollContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="HSeparator2" type="HSeparator" parent="VBoxContainer"]
layout_mode = 2
[node name="BackButton" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Back to Main Menu"
[connection signal="pressed" from="VBoxContainer/BackButton" to="." method="_on_back_button_pressed"]

54
scenes/MainMenu.tscn Normal file
View File

@@ -0,0 +1,54 @@
[gd_scene load_steps=2 format=3 uid="uid://dsrcpteclv0ar"]
[ext_resource type="Script" path="res://scripts/MainMenu.cs" id="1_g4hxb"]
[node name="MainMenu" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource("1_g4hxb")
[node name="Background" type="ColorRect" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
color = Color(0.15, 0.15, 0.25, 1)
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -100.0
offset_top = -100.0
offset_right = 100.0
offset_bottom = 100.0
[node name="TitleLabel" type="Label" parent="VBoxContainer"]
layout_mode = 2
text = "THE GAME"
horizontal_alignment = 1
vertical_alignment = 1
[node name="HSeparator" type="HSeparator" parent="VBoxContainer"]
layout_mode = 2
[node name="StartButton" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Start Game"
[node name="LoadButton" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Load Game"
[node name="ExitButton" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Exit"
[connection signal="pressed" from="VBoxContainer/StartButton" to="." method="_on_start_button_pressed"]
[connection signal="pressed" from="VBoxContainer/LoadButton" to="." method="_on_load_button_pressed"]
[connection signal="pressed" from="VBoxContainer/ExitButton" to="." method="_on_exit_button_pressed"]

76
scripts/Game.cs Normal file
View File

@@ -0,0 +1,76 @@
using Godot;
namespace TheGame
{
public partial class Game : Control
{
private Label _timerLabel;
private Control _pauseMenu;
private float _gameTime = 0.0f;
private bool _isPaused = false;
public override void _Ready()
{
_timerLabel = GetNode<Label>("UI/TimerLabel");
_pauseMenu = GetNode<Control>("PauseMenu");
// Om vi kommer från Load Game, försök ladda sparat tillstånd
if (GameState.LoadedGameTime >= 0)
{
_gameTime = GameState.LoadedGameTime;
GameState.LoadedGameTime = -1; // Reset efter användning
}
}
public override void _Process(double delta)
{
if (!_isPaused)
{
_gameTime += (float)delta;
UpdateTimerDisplay();
}
}
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;
}
}
}

9
scripts/GameState.cs Normal file
View File

@@ -0,0 +1,9 @@
using Godot;
namespace TheGame
{
public static class GameState
{
public static float LoadedGameTime = -1;
}
}

73
scripts/LoadGameMenu.cs Normal file
View File

@@ -0,0 +1,73 @@
using Godot;
using System.Collections.Generic;
namespace TheGame
{
public partial class LoadGameMenu : Control
{
private VBoxContainer _saveList;
private SaveManager _saveManager;
public override void _Ready()
{
_saveList = GetNode<VBoxContainer>("VBoxContainer/ScrollContainer/SaveList");
_saveManager = new SaveManager();
PopulateSaveList();
}
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();
noSavesLabel.Text = "No saved games found";
noSavesLabel.HorizontalAlignment = HorizontalAlignment.Center;
_saveList.AddChild(noSavesLabel);
return;
}
foreach (var saveData in savedGames)
{
var saveButton = new Button();
// Formatera tid för visning
int hours = (int)(saveData.GameTime / 3600);
int minutes = (int)((saveData.GameTime % 3600) / 60);
int seconds = (int)(saveData.GameTime % 60);
string timeText = $"{hours:D2}:{minutes:D2}:{seconds:D2}";
saveButton.Text = $"{saveData.SaveName}\nTime: {timeText}\nSaved: {saveData.SaveDate:yyyy-MM-dd HH:mm:ss}";
// Anslut knapp-händelse
saveButton.Pressed += () => LoadSelectedGame(saveData);
_saveList.AddChild(saveButton);
}
}
private void LoadSelectedGame(SaveData saveData)
{
if (_saveManager.LoadGame(saveData))
{
GetTree().ChangeSceneToFile("res://scenes/Game.tscn");
}
else
{
GD.PrintErr("Failed to load selected game");
}
}
private void _on_back_button_pressed()
{
GetTree().ChangeSceneToFile("res://scenes/MainMenu.tscn");
}
}
}

38
scripts/MainMenu.cs Normal file
View File

@@ -0,0 +1,38 @@
using Godot;
namespace TheGame
{
public partial class MainMenu : Control
{
private Button _loadButton;
public override void _Ready()
{
_loadButton = GetNode<Button>("VBoxContainer/LoadButton");
UpdateLoadButtonState();
}
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()
{
GetTree().ChangeSceneToFile("res://scenes/Game.tscn");
}
private void _on_load_button_pressed()
{
GetTree().ChangeSceneToFile("res://scenes/LoadGameMenu.tscn");
}
private void _on_exit_button_pressed()
{
GetTree().Quit();
}
}
}

40
scripts/PauseMenu.cs Normal file
View File

@@ -0,0 +1,40 @@
using Godot;
namespace TheGame
{
public partial class PauseMenu : Control
{
private Game _gameController;
public override void _Ready()
{
_gameController = GetParent<Game>();
}
private void _on_resume_button_pressed()
{
_gameController.TogglePause();
}
private void _on_save_button_pressed()
{
var saveManager = new SaveManager();
float currentTime = _gameController.GetGameTime();
saveManager.SaveGame(currentTime);
// Visa bekräftelse eller gå tillbaka till spelet
_gameController.TogglePause();
}
private void _on_main_menu_button_pressed()
{
GetTree().Paused = false;
GetTree().ChangeSceneToFile("res://scenes/MainMenu.tscn");
}
private void _on_desktop_button_pressed()
{
GetTree().Quit();
}
}
}

111
scripts/SaveManager.cs Normal file
View File

@@ -0,0 +1,111 @@
using Godot;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
namespace TheGame
{
public class SaveData
{
public float GameTime { get; set; }
public DateTime SaveDate { get; set; }
public string SaveName { get; set; }
}
public class SaveManager
{
private readonly string _saveDirectory;
public SaveManager()
{
_saveDirectory = Path.Combine(OS.GetExecutablePath().GetBaseDir(), "saves");
// Skapa saves mapp om den inte finns
if (!Directory.Exists(_saveDirectory))
{
Directory.CreateDirectory(_saveDirectory);
}
}
public void SaveGame(float gameTime)
{
var saveData = new SaveData
{
GameTime = gameTime,
SaveDate = DateTime.Now,
SaveName = $"Save_{DateTime.Now:yyyyMMdd_HHmmss}"
};
string fileName = $"{saveData.SaveName}.json";
string filePath = Path.Combine(_saveDirectory, fileName);
try
{
string jsonString = JsonSerializer.Serialize(saveData, new JsonSerializerOptions
{
WriteIndented = true
});
File.WriteAllText(filePath, jsonString);
GD.Print($"Game saved successfully: {fileName}");
}
catch (Exception ex)
{
GD.PrintErr($"Failed to save game: {ex.Message}");
}
}
public List<SaveData> GetSavedGames()
{
var savedGames = new List<SaveData>();
if (!Directory.Exists(_saveDirectory))
return savedGames;
try
{
var saveFiles = Directory.GetFiles(_saveDirectory, "*.json");
foreach (string filePath in saveFiles)
{
try
{
string jsonString = File.ReadAllText(filePath);
var saveData = JsonSerializer.Deserialize<SaveData>(jsonString);
if (saveData != null)
{
savedGames.Add(saveData);
}
}
catch (Exception ex)
{
GD.PrintErr($"Failed to load save file {filePath}: {ex.Message}");
}
}
// Sortera efter datum (nyast först)
savedGames.Sort((a, b) => b.SaveDate.CompareTo(a.SaveDate));
}
catch (Exception ex)
{
GD.PrintErr($"Failed to read saves directory: {ex.Message}");
}
return savedGames;
}
public bool LoadGame(SaveData saveData)
{
try
{
GameState.LoadedGameTime = saveData.GameTime;
return true;
}
catch (Exception ex)
{
GD.PrintErr($"Failed to load game: {ex.Message}");
return false;
}
}
}
}