213 lines
8.4 KiB
C#
213 lines
8.4 KiB
C#
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using RecrownedAthenaeum.Render;
|
|
using System;
|
|
using System.Diagnostics;
|
|
|
|
namespace RecrownedAthenaeum.ScreenSystem
|
|
{
|
|
/// <summary>
|
|
/// Called when the first screen is being shown.
|
|
/// </summary>
|
|
/// <param name="screen">The screen to show after the loading screen.</param>
|
|
public delegate void NeedNextScreen(Screen screen);
|
|
|
|
/// <summary>
|
|
/// A manager for screens. Helps with transitions and updating screens as well as resizes.
|
|
/// </summary>
|
|
public class ScreenManager : IDisposable
|
|
{
|
|
bool disposed = false;
|
|
|
|
/// <summary>
|
|
/// Called when the first loading screen is done, and needs to show the landing screen.
|
|
/// </summary>
|
|
public event NeedNextScreen NeedNextScreen;
|
|
|
|
/// <summary>
|
|
/// The settings this manager will use to begin a sprite batch.
|
|
/// </summary>
|
|
private GraphicsDeviceManager graphics;
|
|
private Screen previousScreen;
|
|
private RenderTarget2D previousScreenRenderTarget;
|
|
private Screen currentScreen;
|
|
private bool firstScreenChangeComplete;
|
|
private bool resizing;
|
|
/// <summary>
|
|
/// Currently displayed screen.
|
|
/// </summary>
|
|
public Screen Screen
|
|
{
|
|
get
|
|
{
|
|
return currentScreen;
|
|
}
|
|
set
|
|
{
|
|
previousScreen = currentScreen;
|
|
currentScreen = value;
|
|
if (Screen.width != graphics.PreferredBackBufferWidth || Screen.height != graphics.PreferredBackBufferHeight)
|
|
{
|
|
Screen.ApplySize(graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);
|
|
}
|
|
if (previousScreen != null && previousScreenRenderTarget == null && previousScreen.UseRenderTargetForExitTransition)
|
|
{
|
|
previousScreenRenderTarget = new RenderTarget2D(graphics.GraphicsDevice, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);
|
|
}
|
|
graphics.GraphicsDevice.SetRenderTarget(previousScreenRenderTarget);
|
|
graphics.GraphicsDevice.Clear(Color.Black);
|
|
|
|
Debug.WriteLine("Showing " + value.GetType().Name);
|
|
Screen.Show();
|
|
previousScreen?.Hide();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a screen manager that helps update, draw, and manage multiple screens and their transitions. Uses its own <see cref="SpriteBatch"/>.
|
|
/// </summary>
|
|
/// <param name="graphicsDeviceManager">The graphics device manager to be used.</param>
|
|
public ScreenManager(GraphicsDeviceManager graphicsDeviceManager)
|
|
{
|
|
graphics = graphicsDeviceManager ?? throw new ArgumentNullException("Graphics device manager argument cannot be null.");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the screens. Should be called once every frame.
|
|
/// </summary>
|
|
/// <param name="gameTime">Contains the time that has passed from the last frame.</param>
|
|
/// <param name="waiting">Whether or not there is something a transition should be waiting for. Usually used to wait for assets to complete loading.</param>
|
|
public void UpdateCurrentScreen(GameTime gameTime, bool waiting)
|
|
{
|
|
waiting = !waiting;
|
|
switch (Screen.State)
|
|
{
|
|
case ScreenState.EnterTransition:
|
|
if (previousScreen != null && previousScreen.UseRenderTargetForExitTransition)
|
|
{
|
|
previousScreen.UpdateTransition(gameTime.ElapsedGameTime.TotalSeconds, waiting);
|
|
}
|
|
Screen.UpdateTransition(gameTime.ElapsedGameTime.TotalSeconds, waiting);
|
|
break;
|
|
case ScreenState.ExitTransition:
|
|
if (Screen.UseRenderTargetForExitTransition || Screen.UpdateTransition(gameTime.ElapsedGameTime.TotalSeconds, waiting))
|
|
{
|
|
if (!firstScreenChangeComplete)
|
|
{
|
|
firstScreenChangeComplete = true;
|
|
OnNeedNextScreen(Screen);
|
|
}
|
|
if (Screen.NextScreen != null)
|
|
{
|
|
Debug.WriteLine("Changing to the next given screen.");
|
|
Screen = Screen.NextScreen;
|
|
}
|
|
else if (previousScreen != null)
|
|
{
|
|
Debug.WriteLine("Changing to previous screen.");
|
|
Screen = previousScreen;
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidOperationException("No next screen provided and no previous screen to return to.");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
Screen.Update(gameTime);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Renders screen into window.
|
|
/// Starts and ends the given <paramref name="consistentSpriteBatch"/>.
|
|
/// </summary>
|
|
/// <param name="consistentSpriteBatch">The consistent sprite batch to use. Needs to be consistent as changing render targets requires ending and beginning the sprite batch.</param>
|
|
public void DrawScreen(ConsistentSpriteBatch consistentSpriteBatch)
|
|
{
|
|
if (consistentSpriteBatch == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(consistentSpriteBatch));
|
|
}
|
|
if (Screen == null) return;
|
|
|
|
graphics.GraphicsDevice.Clear(Screen.BackgroundColor);
|
|
if (Screen.State == ScreenState.EnterTransition && previousScreen != null && previousScreen.UseRenderTargetForExitTransition)
|
|
{
|
|
graphics.GraphicsDevice.SetRenderTarget(previousScreenRenderTarget);
|
|
graphics.GraphicsDevice.Clear(previousScreen.BackgroundColor);
|
|
|
|
consistentSpriteBatch.Begin();
|
|
previousScreen.Draw(consistentSpriteBatch);
|
|
consistentSpriteBatch.End();
|
|
|
|
graphics.GraphicsDevice.SetRenderTarget(null);
|
|
Screen.UpdatePreviousScreenFrame(previousScreenRenderTarget);
|
|
}
|
|
|
|
consistentSpriteBatch.Begin();
|
|
Screen.Draw(consistentSpriteBatch);
|
|
consistentSpriteBatch.End();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Should be called when resize is occurring to change to a loading screen.
|
|
/// This will notify the screen of the status of the assets, change the screen to a loading screen, and dispose of the previous screen buffer.
|
|
/// </summary>
|
|
/// <param name="loadingScreen">The loading screen to change to.</param>
|
|
public void Resize(LoadingScreen loadingScreen)
|
|
{
|
|
if (resizing) throw new InvalidOperationException("Already resizing.");
|
|
resizing = true;
|
|
Screen.AssetLoadStateChange(false);
|
|
Screen = loadingScreen;
|
|
previousScreenRenderTarget.Dispose();
|
|
previousScreenRenderTarget = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Notifies all screen that assets have completed being loaded after a resize.
|
|
/// </summary>
|
|
public void PostResize()
|
|
{
|
|
if (!resizing) throw new InvalidOperationException("Was never resizing.");
|
|
Screen.AssetLoadStateChange(true);
|
|
}
|
|
|
|
private void OnNeedNextScreen(Screen screen)
|
|
{
|
|
NeedNextScreen?.Invoke(screen);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disposes this.
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// An overridable dispose.
|
|
/// </summary>
|
|
/// <param name="disposing">True of user invoked dispose called.</param>
|
|
public virtual void Dispose(bool disposing)
|
|
{
|
|
if (disposed) throw new ObjectDisposedException(GetType().Name);
|
|
if (disposing)
|
|
{
|
|
previousScreenRenderTarget?.Dispose();
|
|
}
|
|
disposed = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Destructor.
|
|
/// </summary>
|
|
~ScreenManager()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
}
|
|
}
|