2019-08-06 16:33:49 +02:00
using Coroutine ;
using Microsoft.Xna.Framework ;
2020-05-22 20:32:38 +02:00
using Microsoft.Xna.Framework.Content ;
2019-08-06 16:33:49 +02:00
using Microsoft.Xna.Framework.Graphics ;
2019-08-07 22:25:33 +02:00
using MLEM.Input ;
2019-08-09 23:43:50 +02:00
using MLEM.Ui ;
2019-08-10 21:37:10 +02:00
using MLEM.Ui.Style ;
2019-08-06 16:33:49 +02:00
namespace MLEM.Startup {
2020-05-22 20:32:38 +02:00
/// <summary>
/// MlemGame is an extension of MonoGame's default <see cref="Game"/> class.
/// It features the default template setup, as well as an <see cref="InputHandler"/>, a <see cref="UiSystem"/> and some additional callback events.
/// It also runs all of the <see cref="CoroutineHandler"/> callbacks which can be used through <see cref="CoroutineEvents"/>.
/// </summary>
2019-08-06 16:33:49 +02:00
public class MlemGame : Game {
private static MlemGame instance ;
2020-05-22 20:32:38 +02:00
/// <summary>
/// The static game instance's input handler
/// </summary>
2022-06-15 11:38:11 +02:00
public static InputHandler Input = > MlemGame . instance . InputHandler ;
2019-08-06 16:33:49 +02:00
2020-05-22 20:32:38 +02:00
/// <summary>
/// This game's graphics device manager, initialized in the constructor
/// </summary>
2019-08-06 16:33:49 +02:00
public readonly GraphicsDeviceManager GraphicsDeviceManager ;
2020-05-22 20:32:38 +02:00
/// <summary>
/// This game's sprite batch
/// </summary>
2019-08-07 22:25:33 +02:00
public SpriteBatch SpriteBatch { get ; protected set ; }
2020-05-22 20:32:38 +02:00
/// <summary>
/// This game's input handler. This can easily be accessed through <see cref="Input"/>.
/// </summary>
2019-08-07 22:25:33 +02:00
public InputHandler InputHandler { get ; protected set ; }
2020-05-22 20:32:38 +02:00
/// <summary>
/// This game's ui system
/// </summary>
2019-08-09 23:43:50 +02:00
public UiSystem UiSystem { get ; protected set ; }
2019-08-06 16:33:49 +02:00
2020-05-22 20:32:38 +02:00
/// <summary>
2021-12-13 00:39:36 +01:00
/// An event that is invoked in <see cref="LoadContent"/>.
2020-05-22 20:32:38 +02:00
/// </summary>
2021-06-09 00:27:50 +02:00
public event GenericCallback OnLoadContent ;
2020-05-22 20:32:38 +02:00
/// <summary>
2021-12-13 00:39:36 +01:00
/// An event that is invoked in <see cref="Update"/>, before <see cref="DoUpdate"/> is called.
/// </summary>
public event TimeCallback PreUpdate ;
/// <summary>
/// An event that is invoked in <see cref="Update"/>, after <see cref="DoUpdate"/> is called.
2020-05-22 20:32:38 +02:00
/// </summary>
2021-06-09 00:27:50 +02:00
public event TimeCallback OnUpdate ;
2020-05-22 20:32:38 +02:00
/// <summary>
2021-12-13 00:39:36 +01:00
/// An event that is invoked in <see cref="Draw"/>, before <see cref="DoDraw"/> is called.
/// </summary>
public event TimeCallback PreDraw ;
/// <summary>
/// An event that is invoked in <see cref="Draw"/>, after <see cref="DoDraw"/> is called.
2020-05-22 20:32:38 +02:00
/// </summary>
2021-06-09 00:27:50 +02:00
public event TimeCallback OnDraw ;
2019-09-05 14:27:18 +02:00
2020-05-22 20:32:38 +02:00
/// <summary>
/// Creates a new MlemGame instance with some default settings
/// </summary>
/// <param name="windowWidth">The default window width</param>
/// <param name="windowHeight">The default window height</param>
2020-02-05 22:51:47 +01:00
public MlemGame ( int windowWidth = 1280 , int windowHeight = 720 ) {
2022-06-15 11:38:11 +02:00
MlemGame . instance = this ;
2020-02-05 22:51:47 +01:00
2019-08-06 16:33:49 +02:00
this . GraphicsDeviceManager = new GraphicsDeviceManager ( this ) {
PreferredBackBufferWidth = windowWidth ,
PreferredBackBufferHeight = windowHeight ,
2022-06-24 14:01:26 +02:00
#if ! FNA
2020-02-05 22:51:47 +01:00
HardwareModeSwitch = false
2022-06-24 14:01:26 +02:00
#endif
2019-08-06 16:33:49 +02:00
} ;
2020-02-05 22:51:47 +01:00
this . Window . AllowUserResizing = true ;
this . Content . RootDirectory = "Content" ;
2019-08-06 16:33:49 +02:00
}
2021-11-30 11:46:06 +01:00
/// <summary>
/// Override this to load graphical resources required by the game.
/// </summary>
2019-08-06 16:33:49 +02:00
protected override void LoadContent ( ) {
this . SpriteBatch = new SpriteBatch ( this . GraphicsDevice ) ;
2021-02-18 18:36:29 +01:00
this . InputHandler = new InputHandler ( this ) ;
2019-12-05 17:52:25 +01:00
this . Components . Add ( this . InputHandler ) ;
2021-12-13 00:39:36 +01:00
this . UiSystem = new UiSystem ( this , this . InitializeDefaultUiStyle ( this . SpriteBatch ) , this . InputHandler ) ;
2019-12-05 17:52:25 +01:00
this . Components . Add ( this . UiSystem ) ;
2019-09-05 14:27:18 +02:00
this . OnLoadContent ? . Invoke ( this ) ;
2019-08-06 16:33:49 +02:00
}
2021-11-30 11:46:06 +01:00
/// <summary>
/// Called when the game should update.
/// Updates the <see cref="T:Microsoft.Xna.Framework.GameComponent" /> instances attached to this game.
2021-12-13 00:39:36 +01:00
/// Override <see cref="DoUpdate"/> to update your game.
2021-11-30 11:46:06 +01:00
/// </summary>
/// <param name="gameTime">The elapsed time since the last call to <see cref="M:Microsoft.Xna.Framework.Game.Update(Microsoft.Xna.Framework.GameTime)" />.</param>
2019-12-05 17:35:24 +01:00
protected sealed override void Update ( GameTime gameTime ) {
2021-12-13 00:39:36 +01:00
this . PreUpdate ? . Invoke ( this , gameTime ) ;
CoroutineHandler . RaiseEvent ( CoroutineEvents . PreUpdate ) ;
2019-12-05 17:35:24 +01:00
this . DoUpdate ( gameTime ) ;
2021-12-13 00:39:36 +01:00
2019-09-05 14:27:18 +02:00
this . OnUpdate ? . Invoke ( this , gameTime ) ;
2020-01-30 00:55:02 +01:00
CoroutineHandler . Tick ( gameTime . ElapsedGameTime . TotalSeconds ) ;
2019-08-07 22:25:33 +02:00
CoroutineHandler . RaiseEvent ( CoroutineEvents . Update ) ;
}
2019-08-06 16:33:49 +02:00
2021-11-30 11:46:06 +01:00
/// <summary>
/// Called when the game should draw a frame.
/// Draws the <see cref="T:Microsoft.Xna.Framework.DrawableGameComponent" /> instances attached to this game.
2021-12-13 00:39:36 +01:00
/// Override <see cref="DoDraw"/> to render your game.
2021-11-30 11:46:06 +01:00
/// </summary>
/// <param name="gameTime">A <see cref="T:Microsoft.Xna.Framework.GameTime" /> instance containing the elapsed time since the last call to <see cref="M:Microsoft.Xna.Framework.Game.Draw(Microsoft.Xna.Framework.GameTime)" /> and the total time elapsed since the game started.</param>
2019-12-01 20:25:25 +01:00
protected sealed override void Draw ( GameTime gameTime ) {
2021-12-13 00:39:36 +01:00
this . PreDraw ? . Invoke ( this , gameTime ) ;
CoroutineHandler . RaiseEvent ( CoroutineEvents . PreDraw ) ;
2022-04-08 14:34:57 +02:00
#pragma warning disable CS0618
2022-01-30 16:32:45 +01:00
this . UiSystem . DrawEarly ( gameTime , this . SpriteBatch ) ;
2022-04-08 14:34:57 +02:00
#pragma warning restore CS0618
2019-08-15 14:59:15 +02:00
this . DoDraw ( gameTime ) ;
2019-08-09 23:43:50 +02:00
this . UiSystem . Draw ( gameTime , this . SpriteBatch ) ;
2021-12-13 00:39:36 +01:00
2019-09-05 14:27:18 +02:00
this . OnDraw ? . Invoke ( this , gameTime ) ;
2019-08-07 22:25:33 +02:00
CoroutineHandler . RaiseEvent ( CoroutineEvents . Draw ) ;
2019-08-06 16:33:49 +02:00
}
2020-05-22 20:32:38 +02:00
/// <summary>
/// This method is called in <see cref="Draw"/>.
/// It is the version that should be overridden by implementors to draw game content.
/// </summary>
/// <param name="gameTime">The game's time</param>
2019-08-15 14:59:15 +02:00
protected virtual void DoDraw ( GameTime gameTime ) {
base . Draw ( gameTime ) ;
}
2020-05-22 20:32:38 +02:00
/// <summary>
/// This method is called in <see cref="Update"/>.
/// It is the version that should be overridden by implementors to update game content.
/// </summary>
/// <param name="gameTime">The game's time</param>
2019-12-05 17:35:24 +01:00
protected virtual void DoUpdate ( GameTime gameTime ) {
base . Update ( gameTime ) ;
}
2021-12-13 00:39:36 +01:00
/// <summary>
/// This method is called in <see cref="LoadContent"/> when the <see cref="UiSystem"/> is initialized.
/// Override this method to easily modify or create a new default <see cref="UiStyle"/> for this game's <see cref="UiSystem"/>.
/// </summary>
/// <param name="batch">The sprite batch to use</param>
/// <returns>The <see cref="UiStyle"/> to use for this game's <see cref="UiSystem"/>.</returns>
protected virtual UiStyle InitializeDefaultUiStyle ( SpriteBatch batch ) {
return new UntexturedStyle ( batch ) ;
}
2020-05-22 20:32:38 +02:00
/// <summary>
/// Static helper method for <see cref="ContentManager.Load{T}"/>.
/// This just invokes the game instance's load method.
/// </summary>
/// <param name="name">The name of the content file to load</param>
/// <typeparam name="T">The type of content to load</typeparam>
/// <returns>The loaded content</returns>
2019-08-06 16:33:49 +02:00
public static T LoadContent < T > ( string name ) {
2022-06-15 11:38:11 +02:00
return MlemGame . instance . Content . Load < T > ( name ) ;
2019-08-06 16:33:49 +02:00
}
2020-05-22 20:32:38 +02:00
/// <summary>
/// A delegate method used by <see cref="MlemGame.OnLoadContent"/>.
/// </summary>
/// <param name="game">The game in question</param>
2019-09-05 14:27:18 +02:00
public delegate void GenericCallback ( MlemGame game ) ;
2020-05-22 20:32:38 +02:00
/// <summary>
/// A delegate method used by <see cref="MlemGame.OnUpdate"/> and <see cref="MlemGame.OnDraw"/>.
/// </summary>
/// <param name="game">The game in question</param>
/// <param name="time">The game's current time</param>
2019-09-05 14:27:18 +02:00
public delegate void TimeCallback ( MlemGame game , GameTime time ) ;
2019-08-06 16:33:49 +02:00
}
2022-06-17 18:23:47 +02:00
}