View
223
Download
0
Category
Preview:
Citation preview
The need for screen managementThe front-end to most games will feature a series of navigatable screens (e.g. configuration, high-score, etc.).
Additionally, whilst being played, many games will permit other screens (e.g. options screen) to sometimes appear on top of the main game screen.
Also, the different levels, etc. within a game can also be viewed as a set of screens.
It is desirable to have some means of easily controlling the management (adding, removing, displaying, etc.) of screens.
Management Overview
The following draws upon the
Game State Management XNA tutorial
Game Engineloop {
ScreenManager.Update()ScreenManager.Draw()
}
Game Screen
Update {Update objects()
}
Draw {Draw objects()
}
Screen Manager
Update() { Update screens }
Draw() { Consider screen
rendering}
The core game engine makes use of a screen manager that is responsible for updating and rendering game screens.
The screen manager contains a list of screens to be managed.
The Screen Manager
Aside: The ScreenManager is added to the Game instance as a drawable game component
ScreenManager screenManager = new ScreenManager(this);
Components.Add(screenManager);
public class ScreenManager{ List<GameScreen> screens = new List<GameScreen>(); Stack<GameScreen> screensToUpdate = new Stack<GameScreen>();
InputState input = new InputState();
SpriteBatch spriteBatch;}
• The ScreenManager contains a list of managed GameScreens.
• A stack of GameScreens to be updated is formed each update.
• Input (InputState) and output (SpriteBatch) setup is handled within the Screen Manager and made available to each screen.
Screen Manager (Update() method)
• The input state is evolved for the update tick.
• GameScreens are pushed onto the update stack (screens added last will be updated first)
• Flags are assigned initial values.
public override void Update(GameTime gameTime){
input.Update();
foreach (GameScreen screen in screens) screensToUpdate.Push(screen);
bool otherScreenHasFocus = !Game.IsActive;
bool coveredByOtherScreen = false;
// Update screens...}
while (screensToUpdate.Count > 0){
GameScreen screen = screensToUpdate.Pop();screen.Update(gameTime,
otherScreenHasFocus, coveredByOtherScreen);
if (screen.ScreenState == ScreenState.TransitionOn || screen.ScreenState == ScreenState.Active)
{if (!otherScreenHasFocus){
screen.HandleInput(input); otherScreenHasFocus = true; }
if (!screen.IsPopup) coveredByOtherScreen = true;
}}
• Each screen is updated in reverse add order (those added last are updated first)
• The flags permit context specific screen update
• Only the topmost ‘active’ screen is permitted to handle user input.
public override void Draw(GameTime gameTime){
foreach (GameScreen screen in screens) {
if (screen.ScreenState != ScreenState.Hidden)
screen.Draw(gameTime);}
}
Screen Manager (Draw / Add / Remove)• All non-hidden
screens are asked to draw themselves.
• GameScreens can be added to the manager
public void AddScreen(GameScreen screen){
screen.ScreenManager = this;
screens.Add(screen);}Aside: It is intended that the GameScreen instance will decide
when to remove itself by calling a RemoveScreen method. Think about the usage assumptions this design decision introduces.
The GameScreen
public enum ScreenState {
TransitionOn, Active,
TransitionOff, Hidden }bool isPopup = false;
bool isExiting = false;bool otherScreenHasFocus;
ScreenState screenState = ScreenState.TransitionOn;
TimeSpan transitionOnTime = TimeSpan.Zero;TimeSpan transitionOffTime = TimeSpan.Zero;
• An enumerated type of the valid screen states is defined.
• The GameScreen holds flags defining if it is a pop-up screen (assumed persistent), or if it is currently exiting (valid over several frames), or another screen has the input focus (valid for this update only).
• A fade transition time for the screen appearing and disappearing is also defined.
GameScreen (Update() method)
• The update firstly checks to see if the GameScreen is exiting.
• If not, it then checks to see if it is a covered screen
• If not, it finally checks to see if the screen needs to transition on and become active
public virtual void Update(GameTime gameTime,
bool otherScreenHasFocus, bool coveredByOtherScreen)
{if (isExiting){
// Deal with exit}else if (coveredByOtherScreen){
// Deal with covered screen}else{
// Check for transition on }}
Why is it good to declare this as virtual?
Extending classes will
extend Update() to provide screen
specific behaviour
• If exiting, wait until the fade is complete and then remove the screen
• If covered, fade screen out and enter hidden state
• Otherwise, if screen is not already active, fade it in and make active
if (isExiting){
screenState = ScreenState.TransitionOff;if (!UpdateTransition(gameTime,
transitionOffTime, 1)) ScreenManager.RemoveScreen(this);}
else if (coveredByOtherScreen){
if (UpdateTransition(gameTime, transitionOffTime, 1))
screenState = ScreenState.TransitionOff;else
screenState = ScreenState.Hidden;}
The UpdateTransition method fades the
screen in / out, returning true
whilst doing this and false when
finished
else{
if (UpdateTransition(gameTime, transitionOnTime, -1))
screenState = ScreenState.TransitionOn;else
screenState = ScreenState.Active;}
public virtual void Draw(GameTime gameTime) { }
GameScreen (Draw() method)
• The Draw method is declared virtual, with no inheritable implementation – i.e. it’s up to each game screen how it will be drawn
To explore this tutorial in greater depth, see the Game State Management tutorial from:
http://creators.xna.com/education/
Recommended