69 lines
1.9 KiB
C#
69 lines
1.9 KiB
C#
|
|
using Microsoft.Xna.Framework;
|
||
|
|
using Microsoft.Xna.Framework.Graphics;
|
||
|
|
|
||
|
|
namespace Theriapolis.Game.Screens;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Manages a stack of IScreen instances.
|
||
|
|
/// Only the top screen receives Update and Draw calls.
|
||
|
|
/// Push/Pop are deferred to the start of the next frame to avoid mid-loop mutation.
|
||
|
|
/// </summary>
|
||
|
|
public sealed class ScreenManager
|
||
|
|
{
|
||
|
|
private readonly Game1 _game;
|
||
|
|
private readonly Stack<IScreen> _stack = new();
|
||
|
|
|
||
|
|
private IScreen? _pendingPush;
|
||
|
|
private int _pendingPops; // count rather than bool — multiple Pops queued in one frame all apply
|
||
|
|
|
||
|
|
public ScreenManager(Game1 game)
|
||
|
|
{
|
||
|
|
_game = game;
|
||
|
|
}
|
||
|
|
|
||
|
|
public IScreen? Current => _stack.Count > 0 ? _stack.Peek() : null;
|
||
|
|
|
||
|
|
public void Push(IScreen screen)
|
||
|
|
{
|
||
|
|
_pendingPush = screen;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Pop()
|
||
|
|
{
|
||
|
|
_pendingPops++;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>Process any pending push/pop, then update the current screen.</summary>
|
||
|
|
public void Update(GameTime gameTime)
|
||
|
|
{
|
||
|
|
// Apply deferred transitions — drain all pending pops before any push.
|
||
|
|
bool popped = false;
|
||
|
|
while (_pendingPops > 0 && _stack.Count > 0)
|
||
|
|
{
|
||
|
|
var top = _stack.Pop();
|
||
|
|
top.Deactivate();
|
||
|
|
_pendingPops--;
|
||
|
|
popped = true;
|
||
|
|
}
|
||
|
|
_pendingPops = 0;
|
||
|
|
// Only call Reactivate once after a pop chain — not every frame.
|
||
|
|
if (popped && _stack.TryPeek(out var back)) back.Reactivate();
|
||
|
|
|
||
|
|
if (_pendingPush is not null)
|
||
|
|
{
|
||
|
|
_stack.TryPeek(out var cur);
|
||
|
|
cur?.Deactivate();
|
||
|
|
_pendingPush.Initialize(_game);
|
||
|
|
_stack.Push(_pendingPush);
|
||
|
|
_pendingPush = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
Current?.Update(gameTime);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
|
||
|
|
{
|
||
|
|
Current?.Draw(gameTime, spriteBatch);
|
||
|
|
}
|
||
|
|
}
|