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

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;
}
}
}
}