I'm currently attempting to learn the Monogame system. I have little prior experience in C# (about two weeks of XNA, four years ago) but am reasonably familiar with VB.NET.
Essentially, when calling Game.Exit(), I get the following error:
An unhandled exception of type 'System.NullReferenceException' occurred in MonoGame.Framework.dll
My main class is this:
using System;
namespace MonoTest
{
#if WINDOWS || LINUX
/// <summary>
/// The main class.
/// </summary>
public static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
using (var game = new Game1())
game.Run();
}
}
#endif
}
And the class in which the error occurs is:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace MonoTest
{
/// <summary>
/// This is the main type for your game.
/// </summary>
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
// IMAGES
private Texture2D background;
private Texture2D shuttle;
private Texture2D earth;
private SpriteFont luna24;
private int score;
private AnimatedSprite walker;
private Texture2D arrow;
private float angle = 0;
private int bgTint = 0;
//Keyboard information
KeyboardState state;
KeyboardState oldState; //state from the previous update
//Mouse information
MouseState mState;
MouseState oldMState;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
this.IsMouseVisible = true; //Exactly what it sounds like.
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
background = Content.Load<Texture2D>("bg/stars");
shuttle = Content.Load<Texture2D>("entities/shuttle");
earth = Content.Load<Texture2D>("entities/earth");
luna24 = Content.Load<SpriteFont>("Luna24");
Texture2D walkerTex = Content.Load<Texture2D>("atlases/SmileyWalk");
walker = new AnimatedSprite(walkerTex, 4, 4);
arrow = Content.Load<Texture2D>("entities/arrow");
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// game-specific content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
state = Keyboard.GetState(); //get current state of the keyboard
mState = Mouse.GetState();
//have an oldState value to compare against to check for presses and ignore holds
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
score++;
walker.Update();
if (state.IsKeyDown(Keys.A))
{
angle += 0.01f; //rotate the arrow
}
if (state.IsKeyDown(Keys.Escape))
{
Quit();
//// Monogame's default initialization process seems to run the game without an instance, but that's impossible.
//// Can't think of another explanation.
}
//if (oldState.IsKeyUp(Keys.A) && state.IsKeyDown(Keys.A))
//{
// bgTint += 1;
// if (bgTint > 3)
// {
// bgTint = 0;
// }
//}
//// Above is sample of code to check that a button was pressed *this cycle*.
// If a given button does not exist, it will always appear as released.
if (mState.LeftButton == ButtonState.Pressed && oldMState.LeftButton == ButtonState.Released)
{
bgTint += 1;
if (bgTint > 3)
{
bgTint = 0;
}
Mouse.SetPosition(400, 240);
}
base.Update(gameTime);
oldState = state; //call this at the end of each update loop
oldMState = mState;
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
Vector2 arrowOrigin = new Vector2(20, 100);
Vector2 arrowLoc = new Vector2(400, 240);
Rectangle arrowSource = new Rectangle(0, 0, arrow.Width, arrow.Height);
spriteBatch.Begin();
switch (bgTint)
{
case 0:
spriteBatch.Draw(background, new Rectangle(0, 0, 800, 480), Color.White);
break;
case 1:
spriteBatch.Draw(background, new Rectangle(0, 0, 800, 480), Color.Blue);
break;
case 2:
spriteBatch.Draw(background, new Rectangle(0, 0, 800, 480), Color.Green);
break;
case 3:
spriteBatch.Draw(background, new Rectangle(0, 0, 800, 480), Color.Red);
break;
default:
spriteBatch.Draw(background, new Rectangle(0, 0, 800, 480), Color.White);
break;
}
spriteBatch.DrawString(luna24, "Score: " + score, new Vector2(10, 10), Color.Blue);
spriteBatch.Draw(arrow, arrowLoc, arrowSource, Color.White, angle, arrowOrigin, 1.0f, SpriteEffects.None, 1);
spriteBatch.End();
walker.Draw(spriteBatch, new Vector2(mState.X, mState.Y));
base.Draw(gameTime);
}
private void Quit()
{
if (this != null)
{
Exit(); //this line produces the error
}
}
}
}
As may be apparent, this was created using the standard Monogame project template. The code that seems to be causing the issue is the Quit() method.
private void Quit()
{
if (this != null)
{
Exit(); //this line produces the error
}
}
Quit() is called in Update() when the escape key is pressed. My understanding is that the NullReferenceException would seem to imply that the object Exit() is being called on has not been initialized, but as everything else in the class works as expected I can't see how this could be the case. The stacktrace is below.
at MonoGame.Framework.WinFormsGamePlatform.Exit()
at Microsoft.Xna.Framework.Game.Exit()
at MonoTest.Game1.Quit() in c:\Users\natha\AppData\Local\Temporary Projects\MonoTest\Game1.cs:line 176
at MonoTest.Game1.Update(GameTime gameTime) in c:\Users\natha\AppData\Local\Temporary Projects\MonoTest\Game1.cs:line 103
at Microsoft.Xna.Framework.Game.DoUpdate(GameTime gameTime)
at Microsoft.Xna.Framework.Game.Tick()
at MonoGame.Framework.WinFormsGameWindow.RunLoop()
at MonoGame.Framework.WinFormsGamePlatform.RunLoop()
at Microsoft.Xna.Framework.Game.Run(GameRunBehavior runBehavior)
at Microsoft.Xna.Framework.Game.Run()
at MonoTest.Program.Main() in c:\Users\natha\AppData\Local\Temporary Projects\MonoTest\Program.cs:line 18
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
A temporary resolution has been found. I was able to resolve the issue by replacing the Exit() call on the current object with System.Environment.Exit(). However, this still leaves the issue of why the exception occurred.