feat: lives and death move to the new domain (commit C of the swap)
fixes the regression commit B introduced: coins and skills lived in the Attempt ledger, but nothing discarded it, because LivesStateHandler still called the old store and HandlePlayerDeath was never invoked. Dying kept everything earned that level. Discard-on-death is the ledger's purpose, so it could not be separated from it. new AttemptFailed(remaining, runOver) event, raised after the life is spent and the ledger discarded. DeathScreen and GameOverScreen react to that instead of being wired to HealthComponent.Death by scene connections which fired *before* the life was charged - on the last life game-over saw one life left and showed nothing, then the death screen saw zero and refused to reload. 18 scene connections deleted; the race is now unrepresentable rather than fixed. DeathScreen also had two read paths for lives - a signal and a direct store read - because neither was reliable alone. Now one. Hud reads both facts from signals; only health still polls, and that belongs to the component rather than to progression. GameManager no longer touches GameStateStore or SaveSystem at all.
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
using Godot;
|
||||
using Mr.BrickAdventures.Autoloads;
|
||||
using Mr.BrickAdventures.scripts.Resources;
|
||||
using Mr.BrickAdventures.scripts.State;
|
||||
|
||||
namespace Mr.BrickAdventures.scripts.UI;
|
||||
|
||||
@@ -14,46 +13,49 @@ public partial class DeathScreen : Control
|
||||
[Export] public float TimeoutTime { get; set; } = 2.0f;
|
||||
[Export] public Godot.Collections.Array<Node> NodesToDisable { get; set; } = new();
|
||||
|
||||
private GameManager GameManager => GameManager.Instance;
|
||||
private Timer _timer;
|
||||
private bool _runOver;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
// Subscribe to lives changed event for reactive updates
|
||||
EventBus.Instance.LivesChanged += OnLivesChanged;
|
||||
EventBus.Instance.AttemptFailed += OnAttemptFailed;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
if (EventBus.Instance != null)
|
||||
{
|
||||
EventBus.Instance.LivesChanged -= OnLivesChanged;
|
||||
}
|
||||
EventBus.Instance.AttemptFailed -= OnAttemptFailed;
|
||||
}
|
||||
|
||||
private void OnLivesChanged(int lives)
|
||||
/// <summary>
|
||||
/// Shows the death screen.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Driven by the settled outcome rather than by a scene connection to
|
||||
/// <c>HealthComponent.Death</c>, so the life is already spent and the count already correct. The old
|
||||
/// arrangement read <c>Lives</c> from a handler racing the one that wrote it, then read it a second
|
||||
/// time on timeout — two read paths for one fact, because neither was reliable alone.
|
||||
/// </remarks>
|
||||
private void OnAttemptFailed(int remainingLives, bool runOver)
|
||||
{
|
||||
// Update the label when lives change
|
||||
LivesLeftLabel.Text = $" x {lives}";
|
||||
}
|
||||
_runOver = runOver;
|
||||
LivesLeftLabel.Text = $" x {remainingLives}";
|
||||
|
||||
private void SetLabels()
|
||||
{
|
||||
if (CurrentLevel != null)
|
||||
{
|
||||
CurrentLevelLabel.Text = CurrentLevel.LevelName;
|
||||
}
|
||||
|
||||
// Read current lives from store
|
||||
var lives = GameStateStore.Instance?.Player.Lives ?? 0;
|
||||
LivesLeftLabel.Text = $" x {lives}";
|
||||
ToggleNodes();
|
||||
Show();
|
||||
SetupTimer();
|
||||
}
|
||||
|
||||
private void SetupTimer()
|
||||
{
|
||||
_timer = new Timer();
|
||||
_timer.WaitTime = TimeoutTime;
|
||||
_timer.OneShot = true;
|
||||
_timer = new Timer
|
||||
{
|
||||
WaitTime = TimeoutTime,
|
||||
OneShot = true,
|
||||
};
|
||||
_timer.Timeout += OnTimeout;
|
||||
AddChild(_timer);
|
||||
_timer.Start();
|
||||
@@ -69,21 +71,11 @@ public partial class DeathScreen : Control
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPlayerDeath()
|
||||
{
|
||||
if (GameManager == null) return;
|
||||
|
||||
ToggleNodes();
|
||||
SetLabels();
|
||||
Show();
|
||||
SetupTimer();
|
||||
}
|
||||
|
||||
private void OnTimeout()
|
||||
{
|
||||
var lives = GameStateStore.Instance?.Player.Lives ?? 0;
|
||||
if (lives == 0) return;
|
||||
// Game over is the other screen's job; this one only retries.
|
||||
if (_runOver) return;
|
||||
|
||||
GetTree().ReloadCurrentScene();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user