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:
129
README.md
129
README.md
@@ -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
9
TheGame.csproj
Normal 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
24
TheGame.sln
Normal 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
1
icon.svg
Normal 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
30
project.godot
Normal 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
120
scenes/Game.tscn
Normal 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
54
scenes/LoadGameMenu.tscn
Normal 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
54
scenes/MainMenu.tscn
Normal 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
76
scripts/Game.cs
Normal 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
9
scripts/GameState.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Godot;
|
||||
|
||||
namespace TheGame
|
||||
{
|
||||
public static class GameState
|
||||
{
|
||||
public static float LoadedGameTime = -1;
|
||||
}
|
||||
}
|
||||
73
scripts/LoadGameMenu.cs
Normal file
73
scripts/LoadGameMenu.cs
Normal 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
38
scripts/MainMenu.cs
Normal 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
40
scripts/PauseMenu.cs
Normal 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
111
scripts/SaveManager.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user