Skip to content

Instantly share code, notes, and snippets.

@koenbollen
Created April 18, 2011 14:43
Show Gist options
  • Save koenbollen/925477 to your computer and use it in GitHub Desktop.
Save koenbollen/925477 to your computer and use it in GitHub Desktop.
A simple but complete ScreenManager for XNA.
using Microsoft.Xna.Framework;
using System.Linq;
namespace Screens
{
/// <summary>
/// This is a screen that can be added to the ScreenManager. Extend it and add components
/// to it in the Initialize() method. You can also override the Update() and Draw() method.
/// </summary>
public class Screen : DrawableGameComponent
{
/// <summary>
/// This member tells if this screen is initialized.
/// </summary>
public bool Initialized { get; private set; }
/// <summary>
/// Set this member to true if this screen doesn't cover the entire screen.
/// </summary>
public bool Translucent { get; set; }
/// <summary>
/// A reference to the ScreenManager.
/// </summary>
public ScreenManager Manager { get; internal set; }
/// <summary>
/// The GameComponentCollection, add components for this screen.
/// </summary>
public GameComponentCollection Components { get; private set; }
public Screen(Game game)
: base(game)
{
this.Components = new GameComponentCollection();
Translucent = false;
}
/// <summary>
/// This method is called when this screen is back at the top of the stack.
/// </summary>
public virtual void Activated()
{
}
/// <summary>
/// This method is called when a screen is deactivated by an other screen.
/// </summary>
public virtual void Deactivated()
{
}
/// <summary>
/// Initialize every Component of this screen.
/// </summary>
public override void Initialize()
{
foreach (GameComponent gc in this.Components)
gc.Initialize();
Initialized = true;
base.Initialize();
}
/// <summary>
/// Update every Enabled Component of this screen.
/// </summary>
public override void Update(GameTime gameTime)
{
// Major credits to Nils Dijk:
foreach (IUpdateable gc in this.Components.OfType<IUpdateable>().Where<IUpdateable>(x => x.Enabled).OrderBy<IUpdateable, int>(x => x.UpdateOrder))
gc.Update(gameTime);
base.Update(gameTime);
}
/// <summary>
/// Draw every Visible Component of this screen.
/// </summary>
public override void Draw(GameTime gameTime)
{
// Major credits to Nils Dijk:
foreach (IDrawable gc in this.Components.OfType<IDrawable>().Where<IDrawable>(x => x.Visible).OrderBy<IDrawable,int>(x => x.DrawOrder) )
gc.Draw(gameTime);
base.Draw(gameTime);
}
}
}
using System.Collections.Generic;
using Microsoft.Xna.Framework;
namespace Screens
{
/// <summary>
/// This class is a collection/stack of active screens in the game.
/// A game should have one screen manager and control the active screens by
/// adding and removing screens from this manager.
///
/// The top screen of the stack will be updated and the top screens that are
/// translucent will be drawn. The first screen on the stack that isn't translucent
/// will stop the drawing.
///
/// In Game:
/// public ScreenManager Screens { get; private set; }
///
/// In Game.Initialize():
/// this.Components.Add( this.Screens = new ScreenManager(this, new StartScreen(this)) );
///
/// </summary>
/// By Koen Bollen, 2011
public class ScreenManager : DrawableGameComponent
{
/// <summary>
/// This boolean is set when the Initialize() method is called.
/// </summary>
public bool Initialized { get; private set; }
/// <summary>
/// This is the list of active screens in the game.
/// </summary>
private Stack<Screen> screens;
/// <summary>
/// The current active screen.
/// </summary>
public Screen ActiveScreen
{
get { return this.Peek(); }
}
public ScreenManager(Game game, Screen start)
: base(game)
{
this.screens = new Stack<Screen>();
if( start != null )
this.Push(start);
this.Initialized = false;
}
/// <summary>
/// Initialize all screens in the active screen list.
/// </summary>
public override void Initialize()
{
foreach (Screen s in this.screens)
s.Initialize();
this.Initialized = true;
base.Initialize();
}
/// <summary>
/// Only update the top of the screen stack.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
public override void Update(GameTime gameTime)
{
this.screens.Peek().Update(gameTime);
base.Update(gameTime);
}
/// <summary>
/// Draw all visible screens. A screen that is not translucent will stop the iteration of screens.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
public override void Draw(GameTime gameTime)
{
List<Screen> visible = new List<Screen>();
foreach (Screen s in this.screens)
{
visible.Add(s);
if (!s.Translucent)
break;
}
// Draw from back to front:
for( int i = visible.Count-1; i >= 0; i-- )
visible[i].Draw(gameTime);
base.Draw(gameTime);
}
/// <summary>
/// Add a screen to the top of the stack, if the manager is initialized but the screen isn't initialize it.
/// Also set it's manager to this.
/// </summary>
/// <param name="screen">The screen to add.</param>
public void Push(Screen screen)
{
screen.Manager = this;
if (!screen.Initialized && this.Initialized)
screen.Initialize();
if( this.ActiveScreen != null )
this.ActiveScreen.Deactivated();
this.screens.Push(screen);
}
/// <summary>
/// Get the top of the screen stack. The most active screen.
/// </summary>
/// <returns>The active screen.</returns>
public Screen Peek()
{
if (this.screens.Count < 1 )
return null;
return this.screens.Peek();
}
/// <summary>
/// Remove a screen from the screen stack.
/// </summary>
/// <returns>The removed screen.</returns>
public Screen Pop()
{
if (this.screens.Count < 1)
return null;
Screen prev = this.screens.Pop();
if (this.ActiveScreen != null)
this.ActiveScreen.Activated();
return prev;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment