Reputation: 1
I'm solo working on a video game as a hobby and decided to give MonoGame a try. I'm a beginner so I'm not very knowledgeable. Everything works fine for now, except the game creating a totally useless window when starting the MainMenu scene and leaving the dead Intro window as a leftover. This is not alright, especially as my game will grow and when I will have dozens of scenes. I guess the issue is caused by the fact the Run() instruction creates a new instance for MainMenu when called. I tried a few code snippets, but they seem to simply don't work for my code/specific situation. All I want is the game to keep a single window/instance when switching to different scenes. For now, my game have 3 files: scenes.cs, intro.cs and mainmenu.cs. I will upload their structure here to help you understand better what I'm talking about. I would greatly appreciate some help, thank you!
SCENES.CS:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace MyGame
{
public class Scene : Game
{
protected GraphicsDeviceManager _graphics;
protected SpriteBatch _spriteBatch;
public Scene()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
_graphics.IsFullScreen = true;
_graphics.PreferredBackBufferWidth = 1366;
_graphics.PreferredBackBufferHeight = 768;
_graphics.PreferMultiSampling = false;
_graphics.ApplyChanges();
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
}
public void Switch(Scene scene)
{
Content.Unload();
Exit();
scene.Run();
}
}
}
INTRO.CS:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace MyGame
{
public class Intro : Scene
{
// Constructor
public Intro()
{
}
protected override void Initialize()
{
// Initialization
}
protected override void LoadContent()
{
// Content load
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
// Logo displaying logic
else if (_fadingComplete && _logoDisplayed)
{
Switch(new MainMenu()); // Here I call Switch to switch to the MainMenu scene
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
// Drawing logic
base.Draw(gameTime);
}
}
}
MAINMENU.CS:
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace MyGame
{
public class MainMenu : Scene
{
// Constructor and Initialization
protected override void LoadContent()
{
// Content loading
}
protected override void Update(GameTime gameTime)
{
// Update logic
}
protected override void Draw(GameTime gameTime)
{
// Draw logic
}
}
}
Upvotes: 0
Views: 71
Reputation: 4037
You should not use Game
as a base for anything other than the application itself. Game
is a class that is provided to you to inherit from to make the game itself, not individual parts of it. In it all the other systems (rendering, input, audio, ect.) are implemented for you to use. So it is best to create your own scene-system and manage these scenes in your derived Game class.
First, define your base class to inherit your scenes from
public abstract class Scene
{
public abstract void Initialize();
public abstract void Update(GameTime gameTime);
public abstract void Draw(GameTime gameTime);
public abstract void Deinitialize();
}
Then implement your scenes
public class Intro : Scene
{
public override void Initialize() { /* Your stuff */ }
public override void Update(GameTime gameTime) { /* Your stuff */ }
public override void Draw(GameTime gameTime) { /* Your stuff */ }
public override void Deinitialize() { /* Your stuff */ }
}
public class MainMenu : Scene { /* Implement Stuff */ }
And finally manage the scenes at a central location. Usually, I like having another class inbetween the Game
and the Scene
, but for simplicity sake, I put them directly into Game
, to give you an idea. And also for the sake of demonstration, I made MyGame a Singleton which should be fine here, but don't use it anywhere just because it seems convenient.
public class MyGame : Game
{
public static MyGame MyInstance { get; private set; }
private Scene currentScene;
private Dictionary<Type, Scene> scenes;
public MyGame()
{
Instance = this;
// And the other stuff happening here
}
protected override void Initialize()
{
scenes.Add(typeof(Intro), new Intro);
scenes.Add(typeof(MainMenu), new MainMenu);
SwitchScene<Intro>();
base.Initialize();
}
public void SwitchScene<T>() where T : Scene
{
currentScene?.Deinitialize();
scenes.TryGet(typeof(T), out currentScene);
currentScene?.Initialize();
}
protected override void Update(GameTime gameTime)
{
base.Update(gameTime);
currentScene?.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
currentScene?.Draw(gameTime);
}
}
If you want to switch scenes in this scenario, you are calling SwitchScene
like so:
MyGame.MyInstance.SwitchScene<MainMenu>();
Upvotes: 1