2019-01-13 20:22:53 +00:00
using Microsoft.Xna.Framework ;
2018-11-30 02:41:06 +00:00
using Microsoft.Xna.Framework.Graphics ;
2018-12-04 13:45:09 +00:00
using RecrownedAthenaeum.Camera ;
2018-11-30 02:41:06 +00:00
using System ;
using System.Diagnostics ;
2018-12-04 13:45:09 +00:00
namespace RecrownedAthenaeum.ScreenSystem
2018-11-30 02:41:06 +00:00
{
2019-01-14 05:23:03 +00:00
/// <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 ShowFirstScreen ( Screen screen ) ;
2018-11-30 02:41:06 +00:00
2019-03-09 08:03:05 +00:00
/// <summary>
/// Custom spritebatch begin call.
/// </summary>
/// <param name="spriteBatch"></param>
public delegate void BeginBatch ( SpriteBatch spriteBatch ) ;
2019-01-14 07:26:46 +00:00
/// <summary>
/// A manager for screens. Helps with transitions and updating screens as well as resizes.
/// </summary>
2018-11-30 02:41:06 +00:00
public class ScreenManager : IDisposable
{
2018-12-29 06:23:29 +00:00
bool disposed = false ;
2019-01-14 05:23:03 +00:00
/// <summary>
/// Called when the first loading screen is done, and needs to show the landing screen.
/// </summary>
public event ShowFirstScreen ShowFirstScreenEvent ;
2019-03-09 08:03:05 +00:00
/// <summary>
/// The function to call that begins the batch.
/// </summary>
public BeginBatch beginBatchFunc ;
2019-01-30 13:46:58 +00:00
private GraphicsDeviceManager graphics ;
2018-11-30 02:41:06 +00:00
private Screen previousScreen ;
private RenderTarget2D previousScreenRenderTarget ;
private Screen currentScreen ;
private Camera2D camera ;
private bool firstScreenChangeComplete ;
2019-01-14 05:23:03 +00:00
private bool resizing ;
/// <summary>
/// Currently displayed screen.
/// </summary>
2018-11-30 02:41:06 +00:00
public Screen Screen
{
get
{
return currentScreen ;
}
set
{
previousScreen = currentScreen ;
currentScreen = value ;
if ( ! Screen . Initiated )
{
2019-01-14 07:26:46 +00:00
Screen . Initiate ( new Rectangle ( 0 , 0 , graphics . PreferredBackBufferWidth , graphics . PreferredBackBufferHeight ) , camera ) ;
2018-11-30 02:41:06 +00:00
}
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 ( ) ;
}
}
2019-01-14 05:23:03 +00:00
/// <summary>
/// Creates a screen manager that helps manage multiple screens and their transitions.
/// </summary>
2019-01-30 13:46:58 +00:00
/// <param name="camera">The camera to be used to perform the correct translations and transformations. Will use default set in <see cref="Configuration"/> if left null.</param>
/// <param name="graphicsDeviceManager">The graphics device manager to be used. Will use default set in <see cref="Configuration"/> if left null.</param>
2019-03-09 08:03:05 +00:00
/// <param name="beginBatchFunction">The function to call to begin a batch to be used generally. Will use the built-in one in screen manager if not provided.</param>
public ScreenManager ( Camera2D camera = null , GraphicsDeviceManager graphicsDeviceManager = null , BeginBatch beginBatchFunction = null )
2018-11-30 02:41:06 +00:00
{
2019-03-09 08:03:05 +00:00
if ( beginBatchFunction = = null ) beginBatchFunction = BasicBeginBatch ;
2019-01-30 13:46:58 +00:00
if ( camera = = null ) camera = Configuration . Camera2D ;
if ( graphicsDeviceManager = = null ) graphicsDeviceManager = Configuration . GraphicsDeviceManager ;
graphics = graphicsDeviceManager ? ? throw new ArgumentNullException ( "Graphics device manager argument cannot be null if setup's graphics device manager is also null." ) ;
this . camera = camera ? ? throw new ArgumentNullException ( "2d camera argument cannot be null if setup's 2d camera is also null." ) ;
2019-03-09 08:03:05 +00:00
beginBatchFunc = beginBatchFunction ;
2018-11-30 02:41:06 +00:00
}
2019-01-14 05:23:03 +00:00
/// <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 )
2018-11-30 02:41:06 +00:00
{
switch ( Screen . State )
{
case ScreenState . EnterTransition :
if ( previousScreen ! = null & & previousScreen . UseRenderTargetForExitTransition )
{
2019-01-14 05:23:03 +00:00
previousScreen . UpdateTransition ( gameTime . ElapsedGameTime . TotalSeconds , waiting ) ;
2018-11-30 02:41:06 +00:00
}
2019-01-14 05:23:03 +00:00
Screen . UpdateTransition ( gameTime . ElapsedGameTime . TotalSeconds , waiting ) ;
2018-11-30 02:41:06 +00:00
break ;
case ScreenState . ExitTransition :
2019-01-14 05:23:03 +00:00
if ( Screen . UseRenderTargetForExitTransition | | Screen . UpdateTransition ( gameTime . ElapsedGameTime . TotalSeconds , waiting ) )
2018-11-30 02:41:06 +00:00
{
if ( ! firstScreenChangeComplete )
{
firstScreenChangeComplete = true ;
OnFirstScreenChange ( 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 ) ;
}
2019-01-14 05:23:03 +00:00
/// <summary>
/// Renders screen into window.
/// </summary>
/// <param name="spriteBatch">Uses this batch to render.</param>
2018-11-30 02:41:06 +00:00
public void DrawCurrentScreen ( SpriteBatch spriteBatch )
{
graphics . GraphicsDevice . Clear ( Screen . BackgroundColor ) ;
if ( Screen . State = = ScreenState . EnterTransition & & previousScreen ! = null & & previousScreen . UseRenderTargetForExitTransition )
{
graphics . GraphicsDevice . SetRenderTarget ( previousScreenRenderTarget ) ;
graphics . GraphicsDevice . Clear ( previousScreen . BackgroundColor ) ;
2019-03-09 08:03:05 +00:00
beginBatchFunc ( spriteBatch ) ;
2018-11-30 02:41:06 +00:00
previousScreen . Draw ( spriteBatch ) ;
spriteBatch . End ( ) ;
graphics . GraphicsDevice . SetRenderTarget ( null ) ;
Screen . UpdatePreviousScreenFrame ( previousScreenRenderTarget ) ;
}
2019-03-09 08:03:05 +00:00
beginBatchFunc ( spriteBatch ) ;
2018-11-30 02:41:06 +00:00
Screen . Draw ( spriteBatch ) ;
spriteBatch . End ( ) ;
}
2019-01-14 05:23:03 +00:00
/// <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>
2018-11-30 02:41:06 +00:00
public void Resize ( LoadingScreen loadingScreen )
{
2019-01-14 05:23:03 +00:00
if ( resizing ) throw new InvalidOperationException ( "Already resizing." ) ;
resizing = true ;
Screen . AssetLoadStateChange ( false ) ;
2018-11-30 02:41:06 +00:00
Screen = loadingScreen ;
previousScreenRenderTarget . Dispose ( ) ;
previousScreenRenderTarget = null ;
}
2019-01-14 05:23:03 +00:00
/// <summary>
/// Notifies all screen that assets have completed being loaded after a resize.
/// </summary>
2018-11-30 02:41:06 +00:00
public void PostResize ( )
{
2019-01-14 05:23:03 +00:00
if ( ! resizing ) throw new InvalidOperationException ( "Was never resizing." ) ;
Screen . AssetLoadStateChange ( true ) ;
2018-11-30 02:41:06 +00:00
}
2019-01-14 05:23:03 +00:00
private void OnFirstScreenChange ( Screen screen )
2018-11-30 02:41:06 +00:00
{
2019-01-14 05:23:03 +00:00
ShowFirstScreenEvent ? . Invoke ( screen ) ;
2018-11-30 02:41:06 +00:00
}
2019-01-14 07:26:46 +00:00
/// <summary>
/// Disposes this.
/// </summary>
2018-11-30 02:41:06 +00:00
public void Dispose ( )
{
2018-12-29 06:23:29 +00:00
Dispose ( true ) ;
GC . SuppressFinalize ( this ) ;
}
2019-01-14 07:26:46 +00:00
/// <summary>
/// An overridable dispose.
/// </summary>
/// <param name="disposing">True of user invoked dispose called.</param>
2018-12-29 06:23:29 +00:00
public virtual void Dispose ( bool disposing )
{
if ( disposed ) return ;
if ( disposing )
{
previousScreenRenderTarget ? . Dispose ( ) ;
}
disposing = true ;
2018-11-30 02:41:06 +00:00
}
2019-01-14 07:26:46 +00:00
/// <summary>
/// Destructor.
/// </summary>
~ ScreenManager ( )
{
Dispose ( false ) ;
}
2019-03-09 08:03:05 +00:00
private void BasicBeginBatch ( SpriteBatch spriteBatch )
{
spriteBatch . Begin ( effect : camera . BasicEffect , blendState : BlendState . NonPremultiplied ) ;
}
2018-11-30 02:41:06 +00:00
}
}