Add initial game systems and input handling for player interactions

This commit is contained in:
2025-12-09 22:20:38 +01:00
commit 5e0db113aa
182 changed files with 70557 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
using System;
namespace Core
{
public static class GameEvents
{
// Gameplay Events (Inputs to the systems)
public static event Action<int> PresentCaught;
public static event Action PresentDropped;
// State Changes (Outputs from the systems)
public static event Action<int> ScoreUpdated;
public static event Action<int> LivesUpdated;
public static event Action<float> TimeUpdated;
public static event Action GameOver;
// Invokers
public static void ReportPresentCaught(int value) => PresentCaught?.Invoke(value);
public static void ReportPresentDropped() => PresentDropped?.Invoke();
public static void ReportScoreUpdated(int score) => ScoreUpdated?.Invoke(score);
public static void ReportLivesUpdated(int lives) => LivesUpdated?.Invoke(lives);
public static void ReportTimeUpdated(float time) => TimeUpdated?.Invoke(time);
public static void ReportGameOver() => GameOver?.Invoke();
public static void Clear()
{
// Reset events when scene reloads to prevent memory leaks
PresentCaught = null;
PresentDropped = null;
ScoreUpdated = null;
LivesUpdated = null;
TimeUpdated = null;
GameOver = null;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 26df539822f340e29cceac4ec34dd771
timeCreated: 1765312863

View File

@@ -0,0 +1,8 @@
namespace Core
{
public enum GameMode
{
Arcade,
TimeAttack,
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 53351add092b4030b6c58e9f72380f6d
timeCreated: 1765311817

View File

@@ -0,0 +1,97 @@
using System;
namespace Core
{
public class GameSession
{
public GameMode GameMode { get; private set; }
public int Score { get; private set; }
public int Lives { get; private set; }
public float TimeRemaining { get; private set; }
public bool IsGameOver { get; private set; }
public int HighScore { get; private set; }
public event Action<int> OnScoreChanged;
public event Action<int> OnLivesChanged;
public event Action<float> OnTimeChanged;
public event Action OnGameOver;
private readonly int _initialTimeOrLives;
public GameSession(GameMode gameMode, int initialValue, int currentHighScore)
{
GameMode = gameMode;
Score = 0;
IsGameOver = false;
HighScore = currentHighScore;
switch (gameMode)
{
case GameMode.TimeAttack:
TimeRemaining = initialValue;
Lives = 1;
break;
case GameMode.Arcade:
Lives = initialValue;
TimeRemaining = 0;
break;
}
}
public void Tick(float deltaTime)
{
if (IsGameOver || GameMode != GameMode.TimeAttack) return;
TimeRemaining -= deltaTime;
OnTimeChanged?.Invoke(TimeRemaining);
if (TimeRemaining <= 0)
{
TimeRemaining = 0;
EndGame();
}
}
public void AddScore(int points)
{
if (IsGameOver) return;
Score += points;
OnScoreChanged?.Invoke(Score);
}
public void LoseLife()
{
if (IsGameOver) return;
if (GameMode == GameMode.Arcade)
{
Lives--;
OnLivesChanged?.Invoke(Lives);
}
else
{
TimeRemaining -= _initialTimeOrLives;
OnTimeChanged?.Invoke(TimeRemaining);
}
if (Lives <= 0)
{
Lives = 0;
EndGame();
}
}
private void EndGame()
{
IsGameOver = true;
if (Score > HighScore)
{
HighScore = Score;
}
OnGameOver?.Invoke();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2e5b97c41204455ca44be18f18ddd3b3
timeCreated: 1765307365

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0a13e7537abf404e9a3932ec3f9b4e58
timeCreated: 1765312897

View File

@@ -0,0 +1,35 @@
using System;
namespace Core.Systems
{
public class LivesSystem : IDisposable
{
private int _currentLives;
public LivesSystem(int initialLives)
{
_currentLives = initialLives;
GameEvents.PresentDropped += OnPresentDropped;
GameEvents.ReportLivesUpdated(_currentLives);
}
private void OnPresentDropped()
{
if (_currentLives <= 0) return;
_currentLives--;
GameEvents.ReportLivesUpdated(_currentLives);
if (_currentLives <= 0)
{
GameEvents.ReportGameOver();
}
}
public void Dispose()
{
GameEvents.PresentDropped -= OnPresentDropped;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 694c3777489643ee843bf35f734ac060
timeCreated: 1765312961

View File

@@ -0,0 +1,46 @@
using System;
using Infrastructure;
namespace Core.Systems
{
public class PersistenceSystem : IDisposable
{
private readonly IPersistenceService _service;
private readonly string _saveKey;
private int _currentRunScore;
public PersistenceSystem(IPersistenceService service, string saveKey)
{
_service = service;
_saveKey = saveKey;
GameEvents.ScoreUpdated += OnScoreUpdated;
GameEvents.GameOver += OnGameOver;
}
public int GetHighScore()
{
return _service.LoadHighScore(_saveKey);
}
private void OnGameOver()
{
var existingHighScore = _service.LoadHighScore(_saveKey);
if (_currentRunScore > existingHighScore)
{
_service.SaveHighScore(_saveKey, _currentRunScore);
}
}
private void OnScoreUpdated(int newScore)
{
_currentRunScore = newScore;
}
public void Dispose()
{
GameEvents.ScoreUpdated -= OnScoreUpdated;
GameEvents.GameOver -= OnGameOver;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 99a4c19937ce4a97881d2796dead20d4
timeCreated: 1765313464

View File

@@ -0,0 +1,26 @@
using System;
namespace Core.Systems
{
public class ScoreSystem : IDisposable
{
private int _currentScore;
public ScoreSystem()
{
_currentScore = 0;
GameEvents.PresentCaught += OnPresentCaught;
}
private void OnPresentCaught(int value)
{
_currentScore += value;
GameEvents.ReportScoreUpdated(_currentScore);
}
public void Dispose()
{
GameEvents.PresentCaught -= OnPresentCaught;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9724125bb1674f2e9f8150c290b71d1a
timeCreated: 1765312906

View File

@@ -0,0 +1,51 @@
using System;
namespace Core.Systems
{
public class TimeAttackSystem : IDisposable
{
private float _timeRemaining;
private readonly float _penaltyPerDrop;
public TimeAttackSystem(float initialTime, float penaltyPerDrop = 5f)
{
_timeRemaining = initialTime;
_penaltyPerDrop = penaltyPerDrop;
GameEvents.ReportTimeUpdated(_timeRemaining);
GameEvents.PresentDropped += OnPresentDropped;
}
public void Tick(float deltaTime)
{
if (_timeRemaining <= 0) return;
_timeRemaining -= deltaTime;
if (_timeRemaining <= 0)
{
_timeRemaining = 0;
GameEvents.ReportTimeUpdated(0f);
GameEvents.ReportGameOver();
}
else
{
GameEvents.ReportTimeUpdated(_timeRemaining);
}
}
private void OnPresentDropped()
{
if (_timeRemaining > 0)
{
_timeRemaining -= _penaltyPerDrop;
}
}
public void Dispose()
{
GameEvents.PresentDropped -= OnPresentDropped;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 81bda016e43341779a714e971304d37d
timeCreated: 1765313331