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
|
# 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