diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..76ec77d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.user
+/obj
+/bin
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..162a923
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "FNA"]
+ path = FNA
+ url = git://srchub.org/fna-workbench.git
diff --git a/.vs/GameStateManagement/v14/.suo b/.vs/GameStateManagement/v14/.suo
new file mode 100644
index 0000000..1c131cc
Binary files /dev/null and b/.vs/GameStateManagement/v14/.suo differ
diff --git a/BackgroundScreen.cs b/BackgroundScreen.cs
new file mode 100644
index 0000000..5c1019b
--- /dev/null
+++ b/BackgroundScreen.cs
@@ -0,0 +1,114 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// BackgroundScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using GameStateManagement;
+#endregion
+
+namespace GameStateManagement
+{
+ ///
+ /// The background screen sits behind all the other menu screens.
+ /// It draws a background image that remains fixed in place regardless
+ /// of whatever transitions the screens on top of it may be doing.
+ ///
+ public class BackgroundScreen : GameScreen
+ {
+ #region Fields
+
+ ContentManager content;
+ Texture2D backgroundTexture;
+
+ #endregion
+
+ #region Initialization
+
+
+ ///
+ /// Constructor.
+ ///
+ public BackgroundScreen()
+ {
+ TransitionOnTime = TimeSpan.FromSeconds(0.5);
+ TransitionOffTime = TimeSpan.FromSeconds(0.5);
+ }
+
+
+ ///
+ /// Loads graphics content for this screen. The background texture is quite
+ /// big, so we use our own local ContentManager to load it. This allows us
+ /// to unload before going from the menus into the game itself, wheras if we
+ /// used the shared ContentManager provided by the Game class, the content
+ /// would remain loaded forever.
+ ///
+ public override void Activate(bool instancePreserved)
+ {
+ if (!instancePreserved)
+ {
+ if (content == null)
+ content = new ContentManager(ScreenManager.Game.Services, "Content");
+
+ backgroundTexture = content.Load("background");
+ }
+ }
+
+
+ ///
+ /// Unloads graphics content for this screen.
+ ///
+ public override void Unload()
+ {
+ content.Unload();
+ }
+
+
+ #endregion
+
+ #region Update and Draw
+
+
+ ///
+ /// Updates the background screen. Unlike most screens, this should not
+ /// transition off even if it has been covered by another screen: it is
+ /// supposed to be covered, after all! This overload forces the
+ /// coveredByOtherScreen parameter to false in order to stop the base
+ /// Update method wanting to transition off.
+ ///
+ public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+ bool coveredByOtherScreen)
+ {
+ base.Update(gameTime, otherScreenHasFocus, false);
+ }
+
+
+ ///
+ /// Draws the background screen.
+ ///
+ public override void Draw(GameTime gameTime)
+ {
+ SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+ Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+ Rectangle fullscreen = new Rectangle(0, 0, viewport.Width, viewport.Height);
+
+ spriteBatch.Begin();
+
+ spriteBatch.Draw(backgroundTexture, fullscreen,
+ new Color(TransitionAlpha, TransitionAlpha, TransitionAlpha));
+
+ spriteBatch.End();
+ }
+
+
+ #endregion
+ }
+}
diff --git a/Button.cs b/Button.cs
new file mode 100644
index 0000000..35c0130
--- /dev/null
+++ b/Button.cs
@@ -0,0 +1,191 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// Button.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+using System;
+using GameStateManagement;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace GameStateManagement
+{
+ ///
+ /// A special button that handles toggling between "On" and "Off"
+ ///
+ class BooleanButton : Button
+ {
+ private string option;
+ private bool value;
+
+ ///
+ /// Creates a new BooleanButton.
+ ///
+ /// The string text to display for the option.
+ /// The initial value of the button.
+ public BooleanButton(string option, bool value)
+ : base(option)
+ {
+ this.option = option;
+ this.value = value;
+
+ GenerateText();
+ }
+
+ protected override void OnTapped()
+ {
+ // When tapped we need to toggle the value and regenerate the text
+ value = !value;
+ GenerateText();
+
+ base.OnTapped();
+ }
+
+ ///
+ /// Helper that generates the actual Text value the base class uses for drawing.
+ ///
+ private void GenerateText()
+ {
+ Text = string.Format("{0}: {1}", option, value ? "On" : "Off");
+ }
+ }
+
+ ///
+ /// Represents a touchable button.
+ ///
+ class Button
+ {
+ ///
+ /// The text displayed in the button.
+ ///
+ public string Text = "Button";
+
+ ///
+ /// The position of the top-left corner of the button.
+ ///
+ public Vector2 Position = Vector2.Zero;
+
+ ///
+ /// The size of the button.
+ ///
+ public Vector2 Size = new Vector2(250, 75);
+
+ ///
+ /// The thickness of the border drawn for the button.
+ ///
+ public int BorderThickness = 4;
+
+ ///
+ /// The color of the button border.
+ ///
+ public Color BorderColor = new Color(200, 200, 200);
+
+ ///
+ /// The color of the button background.
+ ///
+ public Color FillColor = new Color(100, 100, 100) * .75f;
+
+ ///
+ /// The color of the text.
+ ///
+ public Color TextColor = Color.White;
+
+ ///
+ /// The opacity of the button.
+ ///
+ public float Alpha = 0f;
+
+ ///
+ /// Invoked when the button is tapped.
+ ///
+ public event EventHandler Tapped;
+
+ ///
+ /// Creates a new Button.
+ ///
+ /// The text to display in the button.
+ public Button(string text)
+ {
+ Text = text;
+ }
+
+ ///
+ /// Invokes the Tapped event and allows subclasses to perform actions when tapped.
+ ///
+ protected virtual void OnTapped()
+ {
+ if (Tapped != null)
+ Tapped(this, EventArgs.Empty);
+ }
+
+ ///
+ /// Passes a tap location to the button for handling.
+ ///
+ /// The location of the tap.
+ /// True if the button was tapped, false otherwise.
+ public bool HandleTap(Vector2 tap)
+ {
+ if (tap.X >= Position.X &&
+ tap.Y >= Position.Y &&
+ tap.X <= Position.X + Size.X &&
+ tap.Y <= Position.Y + Size.Y)
+ {
+ OnTapped();
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Draws the button
+ ///
+ /// The screen drawing the button
+ public void Draw(GameScreen screen)
+ {
+ // Grab some common items from the ScreenManager
+ SpriteBatch spriteBatch = screen.ScreenManager.SpriteBatch;
+ SpriteFont font = screen.ScreenManager.Font;
+ Texture2D blank = screen.ScreenManager.BlankTexture;
+
+ // Compute the button's rectangle
+ Rectangle r = new Rectangle(
+ (int)Position.X,
+ (int)Position.Y,
+ (int)Size.X,
+ (int)Size.Y);
+
+ // Fill the button
+ spriteBatch.Draw(blank, r, FillColor * Alpha);
+
+ // Draw the border
+ spriteBatch.Draw(
+ blank,
+ new Rectangle(r.Left, r.Top, r.Width, BorderThickness),
+ BorderColor * Alpha);
+ spriteBatch.Draw(
+ blank,
+ new Rectangle(r.Left, r.Top, BorderThickness, r.Height),
+ BorderColor * Alpha);
+ spriteBatch.Draw(
+ blank,
+ new Rectangle(r.Right - BorderThickness, r.Top, BorderThickness, r.Height),
+ BorderColor * Alpha);
+ spriteBatch.Draw(
+ blank,
+ new Rectangle(r.Left, r.Bottom - BorderThickness, r.Width, BorderThickness),
+ BorderColor * Alpha);
+
+ // Draw the text centered in the button
+ Vector2 textSize = font.MeasureString(Text);
+ Vector2 textPosition = new Vector2(r.Center.X, r.Center.Y) - textSize / 2f;
+ textPosition.X = (int)textPosition.X;
+ textPosition.Y = (int)textPosition.Y;
+ spriteBatch.DrawString(font, Text, textPosition, TextColor * Alpha);
+ }
+ }
+}
diff --git a/FNA b/FNA
new file mode 160000
index 0000000..4e35338
--- /dev/null
+++ b/FNA
@@ -0,0 +1 @@
+Subproject commit 4e35338d6c3dfb85752b4b94c6ced3223c8b35f5
diff --git a/GameScreen.cs b/GameScreen.cs
new file mode 100644
index 0000000..fd7c803
--- /dev/null
+++ b/GameScreen.cs
@@ -0,0 +1,365 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// GameScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+using System;
+using System.IO;
+using Microsoft.Xna.Framework;
+// TODO: Add Touch API to FNA
+//using Microsoft.Xna.Framework.Input.Touch;
+
+namespace GameStateManagement
+{
+ ///
+ /// Enum describes the screen transition state.
+ ///
+ public enum ScreenState
+ {
+ TransitionOn,
+ Active,
+ TransitionOff,
+ Hidden,
+ }
+
+
+ ///
+ /// A screen is a single layer that has update and draw logic, and which
+ /// can be combined with other layers to build up a complex menu system.
+ /// For instance the main menu, the options menu, the "are you sure you
+ /// want to quit" message box, and the main game itself are all implemented
+ /// as screens.
+ ///
+ public abstract class GameScreen
+ {
+
+ public GameScreen()
+ {
+ HasVirtualStick = false;
+ HasCursor = false;
+ }
+ public bool HasCursor = false;
+ ///
+ /// Normally when one screen is brought up over the top of another,
+ /// the first screen will transition off to make room for the new
+ /// one. This property indicates whether the screen is only a small
+ /// popup, in which case screens underneath it do not need to bother
+ /// transitioning off.
+ ///
+ public bool IsPopup
+ {
+ get { return isPopup; }
+ protected set { isPopup = value; }
+ }
+
+ bool isPopup = false;
+ public bool HasVirtualStick { get; set; }
+
+ ///
+ /// Indicates how long the screen takes to
+ /// transition on when it is activated.
+ ///
+ public TimeSpan TransitionOnTime
+ {
+ get { return transitionOnTime; }
+ protected set { transitionOnTime = value; }
+ }
+
+ TimeSpan transitionOnTime = TimeSpan.Zero;
+
+
+ ///
+ /// Indicates how long the screen takes to
+ /// transition off when it is deactivated.
+ ///
+ public TimeSpan TransitionOffTime
+ {
+ get { return transitionOffTime; }
+ protected set { transitionOffTime = value; }
+ }
+
+ TimeSpan transitionOffTime = TimeSpan.Zero;
+
+
+ ///
+ /// Gets the current position of the screen transition, ranging
+ /// from zero (fully active, no transition) to one (transitioned
+ /// fully off to nothing).
+ ///
+ public float TransitionPosition
+ {
+ get { return transitionPosition; }
+ protected set { transitionPosition = value; }
+ }
+
+ float transitionPosition = 1;
+
+
+ ///
+ /// Gets the current alpha of the screen transition, ranging
+ /// from 1 (fully active, no transition) to 0 (transitioned
+ /// fully off to nothing).
+ ///
+ public float TransitionAlpha
+ {
+ get { return 1f - TransitionPosition; }
+ }
+
+
+ ///
+ /// Gets the current screen transition state.
+ ///
+ public ScreenState ScreenState
+ {
+ get { return screenState; }
+ protected set { screenState = value; }
+ }
+
+ ScreenState screenState = ScreenState.TransitionOn;
+
+
+ ///
+ /// There are two possible reasons why a screen might be transitioning
+ /// off. It could be temporarily going away to make room for another
+ /// screen that is on top of it, or it could be going away for good.
+ /// This property indicates whether the screen is exiting for real:
+ /// if set, the screen will automatically remove itself as soon as the
+ /// transition finishes.
+ ///
+ public bool IsExiting
+ {
+ get { return isExiting; }
+ protected internal set { isExiting = value; }
+ }
+
+ bool isExiting = false;
+
+
+ ///
+ /// Checks whether this screen is active and can respond to user input.
+ ///
+ public bool IsActive
+ {
+ get
+ {
+ return !otherScreenHasFocus &&
+ (screenState == ScreenState.TransitionOn ||
+ screenState == ScreenState.Active);
+ }
+ }
+
+ bool otherScreenHasFocus;
+
+
+ ///
+ /// Gets the manager that this screen belongs to.
+ ///
+ public ScreenManager ScreenManager
+ {
+ get { return screenManager; }
+ internal set { screenManager = value; }
+ }
+
+ ScreenManager screenManager;
+
+
+ ///
+ /// Gets the index of the player who is currently controlling this screen,
+ /// or null if it is accepting input from any player. This is used to lock
+ /// the game to a specific player profile. The main menu responds to input
+ /// from any connected gamepad, but whichever player makes a selection from
+ /// this menu is given control over all subsequent screens, so other gamepads
+ /// are inactive until the controlling player returns to the main menu.
+ ///
+ public PlayerIndex? ControllingPlayer
+ {
+ get { return controllingPlayer; }
+ internal set { controllingPlayer = value; }
+ }
+
+ PlayerIndex? controllingPlayer;
+
+
+ ///
+ /// Gets the gestures the screen is interested in. Screens should be as specific
+ /// as possible with gestures to increase the accuracy of the gesture engine.
+ /// For example, most menus only need Tap or perhaps Tap and VerticalDrag to operate.
+ /// These gestures are handled by the ScreenManager when screens change and
+ /// all gestures are placed in the InputState passed to the HandleInput method.
+ ///
+ /*public GestureType EnabledGestures
+ {
+ get { return enabledGestures; }
+ protected set
+ {
+ enabledGestures = value;
+
+ // the screen manager handles this during screen changes, but
+ // if this screen is active and the gesture types are changing,
+ // we have to update the TouchPanel ourself.
+ if (ScreenState == ScreenState.Active)
+ {
+ TouchPanel.EnabledGestures = value;
+ }
+ }
+ }
+
+ GestureType enabledGestures = GestureType.None;*/
+
+ ///
+ /// Gets whether or not this screen is serializable. If this is true,
+ /// the screen will be recorded into the screen manager's state and
+ /// its Serialize and Deserialize methods will be called as appropriate.
+ /// If this is false, the screen will be ignored during serialization.
+ /// By default, all screens are assumed to be serializable.
+ ///
+ public bool IsSerializable
+ {
+ get { return isSerializable; }
+ protected set { isSerializable = value; }
+ }
+
+ bool isSerializable = true;
+
+
+ ///
+ /// Activates the screen. Called when the screen is added to the screen manager or if the game resumes
+ /// from being paused or tombstoned.
+ ///
+ ///
+ /// True if the game was preserved during deactivation, false if the screen is just being added or if the game was tombstoned.
+ /// On Xbox and Windows this will always be false.
+ ///
+ public virtual void Activate(bool instancePreserved) { }
+
+
+ ///
+ /// Deactivates the screen. Called when the game is being deactivated due to pausing or tombstoning.
+ ///
+ public virtual void Deactivate() { }
+
+
+ ///
+ /// Unload content for the screen. Called when the screen is removed from the screen manager.
+ ///
+ public virtual void Unload() { }
+
+
+ ///
+ /// Allows the screen to run logic, such as updating the transition position.
+ /// Unlike HandleInput, this method is called regardless of whether the screen
+ /// is active, hidden, or in the middle of a transition.
+ ///
+ public virtual void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
+ {
+ this.otherScreenHasFocus = otherScreenHasFocus;
+
+ if (isExiting)
+ {
+ // If the screen is going away to die, it should transition off.
+ screenState = ScreenState.TransitionOff;
+
+ if (!UpdateTransition(gameTime, transitionOffTime, 1))
+ {
+ // When the transition finishes, remove the screen.
+ ScreenManager.RemoveScreen(this);
+ }
+ }
+ else if (coveredByOtherScreen)
+ {
+ // If the screen is covered by another, it should transition off.
+ if (UpdateTransition(gameTime, transitionOffTime, 1))
+ {
+ // Still busy transitioning.
+ screenState = ScreenState.TransitionOff;
+ }
+ else
+ {
+ // Transition finished!
+ screenState = ScreenState.Hidden;
+ }
+ }
+ else
+ {
+ // Otherwise the screen should transition on and become active.
+ if (UpdateTransition(gameTime, transitionOnTime, -1))
+ {
+ // Still busy transitioning.
+ screenState = ScreenState.TransitionOn;
+ }
+ else
+ {
+ // Transition finished!
+ screenState = ScreenState.Active;
+ }
+ }
+ }
+
+
+ ///
+ /// Helper for updating the screen transition position.
+ ///
+ bool UpdateTransition(GameTime gameTime, TimeSpan time, int direction)
+ {
+ // How much should we move by?
+ float transitionDelta;
+
+ if (time == TimeSpan.Zero)
+ transitionDelta = 1;
+ else
+ transitionDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / time.TotalMilliseconds);
+
+ // Update the transition position.
+ transitionPosition += transitionDelta * direction;
+
+ // Did we reach the end of the transition?
+ if (((direction < 0) && (transitionPosition <= 0)) ||
+ ((direction > 0) && (transitionPosition >= 1)))
+ {
+ transitionPosition = MathHelper.Clamp(transitionPosition, 0, 1);
+ return false;
+ }
+
+ // Otherwise we are still busy transitioning.
+ return true;
+ }
+
+
+ ///
+ /// Allows the screen to handle user input. Unlike Update, this method
+ /// is only called when the screen is active, and not when some other
+ /// screen has taken the focus.
+ ///
+ public virtual void HandleInput(GameTime gameTime, InputState input) { }
+
+
+ ///
+ /// This is called when the screen should draw itself.
+ ///
+ public virtual void Draw(GameTime gameTime) { }
+
+
+ ///
+ /// Tells the screen to go away. Unlike ScreenManager.RemoveScreen, which
+ /// instantly kills the screen, this method respects the transition timings
+ /// and will give the screen a chance to gradually transition off.
+ ///
+ public void ExitScreen()
+ {
+ if (TransitionOffTime == TimeSpan.Zero)
+ {
+ // If the screen has a zero transition time, remove it immediately.
+ ScreenManager.RemoveScreen(this);
+ }
+ else
+ {
+ // Otherwise flag that it should transition off and then exit.
+ isExiting = true;
+ }
+ }
+ }
+}
diff --git a/GameStateManagement.csproj b/GameStateManagement.csproj
new file mode 100644
index 0000000..d0d6f56
--- /dev/null
+++ b/GameStateManagement.csproj
@@ -0,0 +1,79 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {A1A96363-C163-4A2A-8F31-D84D80C4C0D7}
+ Library
+ Properties
+ GameStateManagement
+ GameStateManagement
+ v4.5.2
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ x86
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {35253ce1-c864-4cd3-8249-4d1319748e8f}
+ FNA
+
+
+
+
+
\ No newline at end of file
diff --git a/GameStateManagement.sln b/GameStateManagement.sln
new file mode 100644
index 0000000..b240261
--- /dev/null
+++ b/GameStateManagement.sln
@@ -0,0 +1,36 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.24720.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameStateManagement", "GameStateManagement.csproj", "{A1A96363-C163-4A2A-8F31-D84D80C4C0D7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FNA", "FNA\FNA.csproj", "{35253CE1-C864-4CD3-8249-4D1319748E8F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A1A96363-C163-4A2A-8F31-D84D80C4C0D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A1A96363-C163-4A2A-8F31-D84D80C4C0D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A1A96363-C163-4A2A-8F31-D84D80C4C0D7}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A1A96363-C163-4A2A-8F31-D84D80C4C0D7}.Debug|x86.Build.0 = Debug|Any CPU
+ {A1A96363-C163-4A2A-8F31-D84D80C4C0D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A1A96363-C163-4A2A-8F31-D84D80C4C0D7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A1A96363-C163-4A2A-8F31-D84D80C4C0D7}.Release|x86.ActiveCfg = Release|Any CPU
+ {A1A96363-C163-4A2A-8F31-D84D80C4C0D7}.Release|x86.Build.0 = Release|Any CPU
+ {35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|x86.ActiveCfg = Debug|x86
+ {35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|x86.Build.0 = Debug|x86
+ {35253CE1-C864-4CD3-8249-4D1319748E8F}.Release|Any CPU.ActiveCfg = Release|x86
+ {35253CE1-C864-4CD3-8249-4D1319748E8F}.Release|x86.ActiveCfg = Release|x86
+ {35253CE1-C864-4CD3-8249-4D1319748E8F}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/GameplayScreen.cs b/GameplayScreen.cs
new file mode 100644
index 0000000..363eb5f
--- /dev/null
+++ b/GameplayScreen.cs
@@ -0,0 +1,265 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// GameplayScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Threading;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using GameStateManagement;
+#endregion
+
+namespace GameStateManagementSample
+{
+ ///
+ /// This screen implements the actual game logic. It is just a
+ /// placeholder to get the idea across: you'll probably want to
+ /// put some more interesting gameplay in here!
+ ///
+ class GameplayScreen : GameScreen
+ {
+ #region Fields
+
+ ContentManager content;
+ SpriteFont gameFont;
+
+ Vector2 playerPosition = new Vector2(100, 100);
+ Vector2 enemyPosition = new Vector2(100, 100);
+
+ Random random = new Random();
+
+ float pauseAlpha;
+
+ InputAction pauseAction;
+
+ #endregion
+
+ #region Initialization
+
+
+ ///
+ /// Constructor.
+ ///
+ public GameplayScreen()
+ {
+ TransitionOnTime = TimeSpan.FromSeconds(1.5);
+ TransitionOffTime = TimeSpan.FromSeconds(0.5);
+
+ pauseAction = new InputAction(
+ new Buttons[] { Buttons.Start, Buttons.Back },
+ new Keys[] { Keys.Escape },
+ true);
+ }
+
+
+ ///
+ /// Load graphics content for the game.
+ ///
+ public override void Activate(bool instancePreserved)
+ {
+ if (!instancePreserved)
+ {
+ if (content == null)
+ content = new ContentManager(ScreenManager.Game.Services, "Content");
+
+ gameFont = content.Load("gamefont");
+
+ // A real game would probably have more content than this sample, so
+ // it would take longer to load. We simulate that by delaying for a
+ // while, giving you a chance to admire the beautiful loading screen.
+ Thread.Sleep(1000);
+
+ // once the load has finished, we use ResetElapsedTime to tell the game's
+ // timing mechanism that we have just finished a very long frame, and that
+ // it should not try to catch up.
+ ScreenManager.Game.ResetElapsedTime();
+ }
+
+#if WINDOWS_PHONE
+ if (Microsoft.Phone.Shell.PhoneApplicationService.Current.State.ContainsKey("PlayerPosition"))
+ {
+ playerPosition = (Vector2)Microsoft.Phone.Shell.PhoneApplicationService.Current.State["PlayerPosition"];
+ enemyPosition = (Vector2)Microsoft.Phone.Shell.PhoneApplicationService.Current.State["EnemyPosition"];
+ }
+#endif
+ }
+
+
+ public override void Deactivate()
+ {
+#if WINDOWS_PHONE
+ Microsoft.Phone.Shell.PhoneApplicationService.Current.State["PlayerPosition"] = playerPosition;
+ Microsoft.Phone.Shell.PhoneApplicationService.Current.State["EnemyPosition"] = enemyPosition;
+#endif
+
+ base.Deactivate();
+ }
+
+
+ ///
+ /// Unload graphics content used by the game.
+ ///
+ public override void Unload()
+ {
+ content.Unload();
+
+#if WINDOWS_PHONE
+ Microsoft.Phone.Shell.PhoneApplicationService.Current.State.Remove("PlayerPosition");
+ Microsoft.Phone.Shell.PhoneApplicationService.Current.State.Remove("EnemyPosition");
+#endif
+ }
+
+
+ #endregion
+
+ #region Update and Draw
+
+
+ ///
+ /// Updates the state of the game. This method checks the GameScreen.IsActive
+ /// property, so the game will stop updating when the pause menu is active,
+ /// or if you tab away to a different application.
+ ///
+ public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+ bool coveredByOtherScreen)
+ {
+ base.Update(gameTime, otherScreenHasFocus, false);
+
+ // Gradually fade in or out depending on whether we are covered by the pause screen.
+ if (coveredByOtherScreen)
+ pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
+ else
+ pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);
+
+ if (IsActive)
+ {
+ // Apply some random jitter to make the enemy move around.
+ const float randomization = 10;
+
+ enemyPosition.X += (float)(random.NextDouble() - 0.5) * randomization;
+ enemyPosition.Y += (float)(random.NextDouble() - 0.5) * randomization;
+
+ // Apply a stabilizing force to stop the enemy moving off the screen.
+ Vector2 targetPosition = new Vector2(
+ ScreenManager.GraphicsDevice.Viewport.Width / 2 - gameFont.MeasureString("Insert Gameplay Here").X / 2,
+ 200);
+
+ enemyPosition = Vector2.Lerp(enemyPosition, targetPosition, 0.05f);
+
+ // TODO: this game isn't very fun! You could probably improve
+ // it by inserting something more interesting in this space :-)
+ }
+ }
+
+
+ ///
+ /// Lets the game respond to player input. Unlike the Update method,
+ /// this will only be called when the gameplay screen is active.
+ ///
+ public override void HandleInput(GameTime gameTime, InputState input)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+
+ // Look up inputs for the active player profile.
+ int playerIndex = (int)ControllingPlayer.Value;
+
+ KeyboardState keyboardState = input.CurrentKeyboardStates[playerIndex];
+ GamePadState gamePadState = input.CurrentGamePadStates[playerIndex];
+
+ // The game pauses either if the user presses the pause button, or if
+ // they unplug the active gamepad. This requires us to keep track of
+ // whether a gamepad was ever plugged in, because we don't want to pause
+ // on PC if they are playing with a keyboard and have no gamepad at all!
+ bool gamePadDisconnected = !gamePadState.IsConnected &&
+ input.GamePadWasConnected[playerIndex];
+
+ PlayerIndex player;
+ if (pauseAction.Evaluate(input, ControllingPlayer, out player) || gamePadDisconnected)
+ {
+#if WINDOWS_PHONE
+ ScreenManager.AddScreen(new PhonePauseScreen(), ControllingPlayer);
+#else
+ ScreenManager.AddScreen(new PauseMenuScreen(), ControllingPlayer);
+#endif
+ }
+ else
+ {
+ // Otherwise move the player position.
+ Vector2 movement = Vector2.Zero;
+
+ if (keyboardState.IsKeyDown(Keys.Left))
+ movement.X--;
+
+ if (keyboardState.IsKeyDown(Keys.Right))
+ movement.X++;
+
+ if (keyboardState.IsKeyDown(Keys.Up))
+ movement.Y--;
+
+ if (keyboardState.IsKeyDown(Keys.Down))
+ movement.Y++;
+
+ Vector2 thumbstick = gamePadState.ThumbSticks.Left;
+
+ movement.X += thumbstick.X;
+ movement.Y -= thumbstick.Y;
+
+ /*if (input.TouchState.Count > 0)
+ {
+ Vector2 touchPosition = input.TouchState[0].Position;
+ Vector2 direction = touchPosition - playerPosition;
+ direction.Normalize();
+ movement += direction;
+ }*/
+
+ if (movement.Length() > 1)
+ movement.Normalize();
+
+ playerPosition += movement * 8f;
+ }
+ }
+
+
+ ///
+ /// Draws the gameplay screen.
+ ///
+ public override void Draw(GameTime gameTime)
+ {
+ // This game has a blue background. Why? Because!
+ ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
+ Color.CornflowerBlue, 0, 0);
+
+ // Our player and enemy are both actually just text strings.
+ SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+
+ spriteBatch.Begin();
+
+ spriteBatch.DrawString(gameFont, "// TODO", playerPosition, Color.Green);
+
+ spriteBatch.DrawString(gameFont, "Insert Gameplay Here",
+ enemyPosition, Color.DarkRed);
+
+ spriteBatch.End();
+
+ // If the game is transitioning on or off, fade it out to black.
+ if (TransitionPosition > 0 || pauseAlpha > 0)
+ {
+ float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);
+
+ ScreenManager.FadeBackBufferToBlack(alpha);
+ }
+ }
+
+
+ #endregion
+ }
+}
diff --git a/IScreenFactory.cs b/IScreenFactory.cs
new file mode 100644
index 0000000..f9fb2b6
--- /dev/null
+++ b/IScreenFactory.cs
@@ -0,0 +1,49 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// IScreenFactory.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+using System;
+
+namespace GameStateManagement
+{
+ ///
+ /// Defines an object that can create a screen when given its type.
+ ///
+ /// The ScreenManager attempts to handle tombstoning on Windows Phone by creating an XML
+ /// document that has a list of the screens currently in the manager. When the game is
+ /// reactivated, the ScreenManager needs to create instances of those screens. However
+ /// since there is no restriction that a particular GameScreen subclass has a parameterless
+ /// constructor, there is no way the ScreenManager alone could create those instances.
+ ///
+ /// IScreenFactory fills this gap by providing an interface the game should implement to
+ /// act as a translation from type to instance. The ScreenManager locates the IScreenFactory
+ /// from the Game.Services collection and passes each screen type to the factory, expecting
+ /// to get the correct GameScreen out.
+ ///
+ /// If your game screens all have parameterless constructors, the minimal implementation of
+ /// this interface would look like this:
+ ///
+ /// return Activator.CreateInstance(screenType) as GameScreen;
+ ///
+ /// If you have screens with constructors that take arguments, you will need to ensure that
+ /// you can read these arguments from storage or generate new ones, then construct the screen
+ /// based on the type.
+ ///
+ /// The ScreenFactory type in the sample game has the minimal implementation along with some
+ /// extra comments showing a potentially more complex example of how to implement IScreenFactory.
+ ///
+ public interface IScreenFactory
+ {
+ ///
+ /// Creates a GameScreen from the given type.
+ ///
+ /// The type of screen to create.
+ /// The newly created screen.
+ GameScreen CreateScreen(Type screenType);
+ }
+}
diff --git a/InputAction.cs b/InputAction.cs
new file mode 100644
index 0000000..302c051
--- /dev/null
+++ b/InputAction.cs
@@ -0,0 +1,96 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// InputAction.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Input;
+
+namespace GameStateManagement
+{
+ ///
+ /// Defines an action that is designated by some set of buttons and/or keys.
+ ///
+ /// The way actions work is that you define a set of buttons and keys that trigger the action. You can
+ /// then evaluate the action against an InputState which will test to see if any of the buttons or keys
+ /// are pressed by a player. You can also set a flag that indicates if the action only occurs once when
+ /// the buttons/keys are first pressed or whether the action should occur each frame.
+ ///
+ /// Using this InputAction class means that you can configure new actions based on keys and buttons
+ /// without having to directly modify the InputState type. This means more customization by your games
+ /// without having to change the core classes of Game State Management.
+ ///
+ public class InputAction
+ {
+ private readonly Buttons[] buttons;
+ private readonly Keys[] keys;
+ private readonly bool newPressOnly;
+
+ // These delegate types map to the methods on InputState. We use these to simplify the evalute method
+ // by allowing us to map the appropriate delegates and invoke them, rather than having two separate code paths.
+ private delegate bool ButtonPress(Buttons button, PlayerIndex? controllingPlayer, out PlayerIndex player);
+ private delegate bool KeyPress(Keys key, PlayerIndex? controllingPlayer, out PlayerIndex player);
+
+ ///
+ /// Initializes a new InputAction.
+ ///
+ /// An array of buttons that can trigger the action.
+ /// An array of keys that can trigger the action.
+ /// Whether the action only occurs on the first press of one of the buttons/keys,
+ /// false if it occurs each frame one of the buttons/keys is down.
+ public InputAction(Buttons[] buttons, Keys[] keys, bool newPressOnly)
+ {
+ // Store the buttons and keys. If the arrays are null, we create a 0 length array so we don't
+ // have to do null checks in the Evaluate method
+ this.buttons = buttons != null ? buttons.Clone() as Buttons[] : new Buttons[0];
+ this.keys = keys != null ? keys.Clone() as Keys[] : new Keys[0];
+
+ this.newPressOnly = newPressOnly;
+ }
+
+ ///
+ /// Evaluates the action against a given InputState.
+ ///
+ /// The InputState to test for the action.
+ /// The player to test, or null to allow any player.
+ /// If controllingPlayer is null, this is the player that performed the action.
+ /// True if the action occurred, false otherwise.
+ public bool Evaluate(InputState state, PlayerIndex? controllingPlayer, out PlayerIndex player)
+ {
+ // Figure out which delegate methods to map from the state which takes care of our "newPressOnly" logic
+ ButtonPress buttonTest;
+ KeyPress keyTest;
+ if (newPressOnly)
+ {
+ buttonTest = state.IsNewButtonPress;
+ keyTest = state.IsNewKeyPress;
+ }
+ else
+ {
+ buttonTest = state.IsButtonPressed;
+ keyTest = state.IsKeyPressed;
+ }
+
+ // Now we simply need to invoke the appropriate methods for each button and key in our collections
+ foreach (Buttons button in buttons)
+ {
+ if (buttonTest(button, controllingPlayer, out player))
+ return true;
+ }
+ foreach (Keys key in keys)
+ {
+ if (keyTest(key, controllingPlayer, out player))
+ return true;
+ }
+
+ // If we got here, the action is not matched
+ player = PlayerIndex.One;
+ return false;
+ }
+ }
+}
diff --git a/InputState.cs b/InputState.cs
new file mode 100644
index 0000000..8c9f800
--- /dev/null
+++ b/InputState.cs
@@ -0,0 +1,608 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// InputState.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Input;
+//using Microsoft.Xna.Framework.Input.Touch;
+//using FarseerPhysics.SamplesFramework;
+using Microsoft.Xna.Framework.Graphics;
+using System;
+using System.Linq;
+
+
+namespace GameStateManagement
+{
+
+ ///
+ /// an enum of all available mouse buttons.
+ ///
+ public enum MouseButtons
+ {
+ LeftButton,
+ MiddleButton,
+ RightButton,
+ ExtraButton1,
+ ExtraButton2
+ }
+
+ ///
+ /// Helper for reading input from keyboard, gamepad, and touch input. This class
+ /// tracks both the current and previous state of the input devices, and implements
+ /// query methods for high level input actions such as "move up through the menu"
+ /// or "pause the game".
+ ///
+ public class InputState
+ {
+ public const int MaxInputs = 4;
+
+ public readonly KeyboardState[] CurrentKeyboardStates;
+ public readonly GamePadState[] CurrentGamePadStates;
+
+ public readonly KeyboardState[] LastKeyboardStates;
+ public readonly GamePadState[] LastGamePadStates;
+
+ public readonly bool[] GamePadWasConnected;
+
+ /*
+ * Needed for virtual stick on WP7
+ * -- Nathan Adams [adamsna@datanethost.net] - 4/12/2012
+ */
+ private GamePadState _currentVirtualState;
+ private GamePadState _lastVirtualState;
+ private bool _handleVirtualStick;
+ /*
+ * I didn't create an array for the virtual stick because there will only be one
+ * -- Nathan Adams [adamsna@datanethost.net] - 4/12/2012
+ */
+
+
+ /*
+ * Adding variables for the cursor
+ * -- Nathan Adams [adamsna@datanethost.net] - 4/15/2012
+ *
+ */
+ private MouseState _currentMouseState;
+ private MouseState _lastMouseState;
+
+ private Vector2 _cursor;
+ private bool _cursorIsValid;
+ private bool _cursorIsVisible;
+ private bool _cursorMoved;
+ private Texture2D _cursorSprite;
+
+#if WINDOWS_PHONE
+ private VirtualStick _phoneStick;
+ private VirtualButton _phoneA;
+ private VirtualButton _phoneB;
+#endif
+
+ //public TouchCollection TouchState;
+
+ //public readonly List Gestures = new List();
+
+ private ScreenManager _manager;
+ private Viewport _viewport;
+
+
+ ///
+ /// Constructs a new input state.
+ ///
+ public InputState(ScreenManager manager)
+ {
+ _manager = manager;
+ CurrentKeyboardStates = new KeyboardState[MaxInputs];
+ CurrentGamePadStates = new GamePadState[MaxInputs];
+
+ LastKeyboardStates = new KeyboardState[MaxInputs];
+ LastGamePadStates = new GamePadState[MaxInputs];
+
+ GamePadWasConnected = new bool[MaxInputs];
+ _currentVirtualState = new GamePadState();
+ _lastVirtualState = new GamePadState();
+
+ _cursorIsVisible = false;
+ _cursorMoved = false;
+#if WINDOWS_PHONE
+ _cursorIsValid = false;
+#else
+ _cursorIsValid = true;
+#endif
+ _cursor = Vector2.Zero;
+
+ _handleVirtualStick = false;
+ }
+
+ public MouseState MouseState
+ {
+ get { return _currentMouseState; }
+ }
+
+ public GamePadState VirtualState
+ {
+ get { return _currentVirtualState; }
+ }
+
+ public MouseState PreviousMouseState
+ {
+ get { return _lastMouseState; }
+ }
+
+ public GamePadState PreviousVirtualState
+ {
+ get { return _lastVirtualState; }
+ }
+
+ public bool ShowCursor
+ {
+ get { return _cursorIsVisible && _cursorIsValid; }
+ set { _cursorIsVisible = value; }
+ }
+
+ public bool EnableVirtualStick
+ {
+ get { return _handleVirtualStick; }
+ set { _handleVirtualStick = value; }
+ }
+
+ public Vector2 Cursor
+ {
+ get { return _cursor; }
+ }
+
+ public bool IsCursorMoved
+ {
+ get { return _cursorMoved; }
+ }
+
+ public bool IsCursorValid
+ {
+ get { return _cursorIsValid; }
+ }
+
+ public void LoadContent()
+ {
+ ContentManager man = new ContentManager(_manager.Game.Services, "Content");
+ //_cursorSprite = new Sprite(man.Load("Common/cursor"));
+ _cursorSprite = man.Load("Common/cursor");
+#if WINDOWS_PHONE
+ // virtual stick content
+ _phoneStick = new VirtualStick(man.Load("Common/socket"),
+ man.Load("Common/stick"), new Vector2(80f, 400f));
+
+ Texture2D temp = man.Load("Common/buttons");
+ _phoneA = new VirtualButton(temp, new Vector2(695f, 380f), new Rectangle(0, 0, 40, 40), new Rectangle(0, 40, 40, 40));
+ _phoneB = new VirtualButton(temp, new Vector2(745f, 360f), new Rectangle(40, 0, 40, 40), new Rectangle(40, 40, 40, 40));
+#endif
+ _viewport = _manager.GraphicsDevice.Viewport;
+ }
+
+ private GamePadState HandleVirtualStickWin()
+ {
+ Vector2 _leftStick = Vector2.Zero;
+ List _buttons = new List();
+ PlayerIndex pout;
+ if (IsNewKeyPress(Keys.A, PlayerIndex.One, out pout))
+ {
+ _leftStick.X -= 1f;
+ }
+ if (IsNewKeyPress(Keys.S, PlayerIndex.One, out pout))
+ {
+ _leftStick.Y -= 1f;
+ }
+ if (IsNewKeyPress(Keys.D, PlayerIndex.One, out pout))
+ {
+ _leftStick.X += 1f;
+ }
+ if (IsNewKeyPress(Keys.W, PlayerIndex.One, out pout))
+ {
+ _leftStick.Y += 1f;
+ }
+ if (IsNewKeyPress(Keys.Space, PlayerIndex.One, out pout))
+ {
+ _buttons.Add(Buttons.A);
+ }
+ if (IsNewKeyPress(Keys.LeftControl, PlayerIndex.One, out pout))
+ {
+ _buttons.Add(Buttons.B);
+ }
+ if (_leftStick != Vector2.Zero)
+ {
+ _leftStick.Normalize();
+ }
+
+ return new GamePadState(_leftStick, Vector2.Zero, 0f, 0f, _buttons.ToArray());
+ }
+
+ private GamePadState HandleVirtualStickWP7()
+ {
+ List _buttons = new List();
+ Vector2 _stick = Vector2.Zero;
+#if WINDOWS_PHONE
+ _phoneA.Pressed = false;
+ _phoneB.Pressed = false;
+ TouchCollection touchLocations = TouchPanel.GetState();
+ foreach (TouchLocation touchLocation in touchLocations)
+ {
+ _phoneA.Update(touchLocation);
+ _phoneB.Update(touchLocation);
+ _phoneStick.Update(touchLocation);
+ }
+ if (_phoneA.Pressed)
+ {
+ _buttons.Add(Buttons.A);
+ }
+ if (_phoneB.Pressed)
+ {
+ _buttons.Add(Buttons.B);
+ }
+ _stick = _phoneStick.StickPosition;
+#endif
+ return new GamePadState(_stick, Vector2.Zero, 0f, 0f, _buttons.ToArray());
+ }
+
+ public void Draw()
+ {
+ if (_cursorIsVisible && _cursorIsValid)
+ {
+ _manager.SpriteBatch.Begin();
+ _manager.SpriteBatch.Draw(_cursorSprite, _cursor, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0f);
+ _manager.SpriteBatch.End();
+ }
+#if WINDOWS_PHONE
+ if (_handleVirtualStick)
+ {
+ _manager.SpriteBatch.Begin();
+ _phoneA.Draw(_manager.SpriteBatch);
+ _phoneB.Draw(_manager.SpriteBatch);
+ _phoneStick.Draw(_manager.SpriteBatch);
+ _manager.SpriteBatch.End();
+ }
+#endif
+ }
+
+ ///
+ /// Reads the latest state user input.
+ ///
+ public void Update(GameTime gameTime)
+ {
+ _lastMouseState = _currentMouseState;
+ if (_handleVirtualStick)
+ {
+ _lastVirtualState = _currentVirtualState;
+ }
+
+ _currentMouseState = Mouse.GetState();
+
+ if (_handleVirtualStick)
+ {
+#if XBOX
+ _currentVirtualState= GamePad.GetState(PlayerIndex.One);
+#elif WINDOWS
+ if (GamePad.GetState(PlayerIndex.One).IsConnected)
+ {
+ _currentVirtualState = GamePad.GetState(PlayerIndex.One);
+ }
+ else
+ {
+ _currentVirtualState = HandleVirtualStickWin();
+ }
+#elif WINDOWS_PHONE
+ _currentVirtualState = HandleVirtualStickWP7();
+#endif
+ }
+ for (int i = 0; i < MaxInputs; i++)
+ {
+ LastKeyboardStates[i] = CurrentKeyboardStates[i];
+ LastGamePadStates[i] = CurrentGamePadStates[i];
+
+ CurrentKeyboardStates[i] = Keyboard.GetState();
+ CurrentGamePadStates[i] = GamePad.GetState((PlayerIndex)i);
+
+ // Keep track of whether a gamepad has ever been
+ // connected, so we can detect if it is unplugged.
+ if (CurrentGamePadStates[i].IsConnected)
+ {
+ GamePadWasConnected[i] = true;
+ }
+ }
+
+ // Get the raw touch state from the TouchPanel
+ //TouchState = TouchPanel.GetState();
+
+ // Read in any detected gestures into our list for the screens to later process
+ //Gestures.Clear();
+ /*while (TouchPanel.IsGestureAvailable)
+ {
+ //System.Diagnostics.Debugger.Break();
+ Gestures.Add(TouchPanel.ReadGesture());
+ }*/
+ //System.Diagnostics.Debugger.Break();
+
+ // Update cursor
+ Vector2 oldCursor = _cursor;
+
+ if (CurrentGamePadStates[0].IsConnected && CurrentGamePadStates[0].ThumbSticks.Left != Vector2.Zero)
+ {
+ Vector2 temp = CurrentGamePadStates[0].ThumbSticks.Left;
+ _cursor += temp * new Vector2(300f, -300f) * (float)gameTime.ElapsedGameTime.TotalSeconds;
+ Mouse.SetPosition((int)_cursor.X, (int)_cursor.Y);
+ }
+ else
+ {
+ _cursor.X = _currentMouseState.X;
+ _cursor.Y = _currentMouseState.Y;
+ }
+
+ //if (this.IsNewKeyPress(Keys.P, PlayerIndex.One, out p))
+ // Console.WriteLine(_cursor.ToString());
+
+ _cursor.X = MathHelper.Clamp(_cursor.X, 0f, _viewport.Width);
+ _cursor.Y = MathHelper.Clamp(_cursor.Y, 0f, _viewport.Height);
+
+ //if (this.IsNewKeyPress(Keys.P, PlayerIndex.One, out p))
+ // Console.WriteLine(_cursor.ToString());
+
+ if (_cursorIsValid && oldCursor != _cursor)
+ {
+ _cursorMoved = true;
+ }
+ else
+ {
+ _cursorMoved = false;
+ }
+
+#if WINDOWS
+ if (_viewport.Bounds.Contains(_currentMouseState.X, _currentMouseState.Y))
+ {
+ _cursorIsValid = true;
+ }
+ else
+ {
+ _cursorIsValid = false;
+ }
+#elif WINDOWS_PHONE
+ if (_currentMouseState.LeftButton == ButtonState.Pressed)
+ {
+ _cursorIsValid = true;
+ }
+ else
+ {
+ _cursorIsValid = false;
+ }
+#endif
+
+ //if (this.IsNewKeyPress(Keys.P, PlayerIndex.One, out p))
+ // Console.WriteLine(_viewport.ToString());
+ }
+
+
+ ///
+ /// Helper for checking if a key was pressed during this update. The
+ /// controllingPlayer parameter specifies which player to read input for.
+ /// If this is null, it will accept input from any player. When a keypress
+ /// is detected, the output playerIndex reports which player pressed it.
+ ///
+ public bool IsKeyPressed(Keys key, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
+ {
+ if (controllingPlayer.HasValue)
+ {
+ // Read input from the specified player.
+ playerIndex = controllingPlayer.Value;
+
+ int i = (int)playerIndex;
+
+ return CurrentKeyboardStates[i].IsKeyDown(key);
+ }
+ else
+ {
+ // Accept input from any player.
+ return (IsKeyPressed(key, PlayerIndex.One, out playerIndex) ||
+ IsKeyPressed(key, PlayerIndex.Two, out playerIndex) ||
+ IsKeyPressed(key, PlayerIndex.Three, out playerIndex) ||
+ IsKeyPressed(key, PlayerIndex.Four, out playerIndex));
+ }
+ }
+
+ ///
+ /// Helper for checking if a button was pressed during this update.
+ /// The controllingPlayer parameter specifies which player to read input for.
+ /// If this is null, it will accept input from any player. When a button press
+ /// is detected, the output playerIndex reports which player pressed it.
+ ///
+ public bool IsButtonPressed(Buttons button, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
+ {
+ if (controllingPlayer.HasValue)
+ {
+ // Read input from the specified player.
+ playerIndex = controllingPlayer.Value;
+
+ int i = (int)playerIndex;
+
+ return CurrentGamePadStates[i].IsButtonDown(button);
+ }
+ else
+ {
+ // Accept input from any player.
+ return (IsButtonPressed(button, PlayerIndex.One, out playerIndex) ||
+ IsButtonPressed(button, PlayerIndex.Two, out playerIndex) ||
+ IsButtonPressed(button, PlayerIndex.Three, out playerIndex) ||
+ IsButtonPressed(button, PlayerIndex.Four, out playerIndex));
+ }
+ }
+
+ ///
+ /// Helper for checking if a key was newly pressed during this update. The
+ /// controllingPlayer parameter specifies which player to read input for.
+ /// If this is null, it will accept input from any player. When a keypress
+ /// is detected, the output playerIndex reports which player pressed it.
+ ///
+ public bool IsNewKeyPress(Keys key, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
+ {
+ if (controllingPlayer.HasValue)
+ {
+ // Read input from the specified player.
+ playerIndex = controllingPlayer.Value;
+
+ int i = (int)playerIndex;
+
+ return (CurrentKeyboardStates[i].IsKeyDown(key) &&
+ LastKeyboardStates[i].IsKeyUp(key));
+ }
+ else
+ {
+ // Accept input from any player.
+ return (IsNewKeyPress(key, PlayerIndex.One, out playerIndex) ||
+ IsNewKeyPress(key, PlayerIndex.Two, out playerIndex) ||
+ IsNewKeyPress(key, PlayerIndex.Three, out playerIndex) ||
+ IsNewKeyPress(key, PlayerIndex.Four, out playerIndex));
+ }
+ }
+
+ public bool IsNewKeyRelease(Keys key, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
+ {
+ if (controllingPlayer.HasValue)
+ {
+ // Read input from the specified player.
+ playerIndex = controllingPlayer.Value;
+
+ int i = (int)playerIndex;
+
+ return (CurrentKeyboardStates[i].IsKeyUp(key) &&
+ LastKeyboardStates[i].IsKeyDown(key));
+ }
+ else
+ {
+ // Accept input from any player.
+ return (IsNewKeyRelease(key, PlayerIndex.One, out playerIndex) ||
+ IsNewKeyRelease(key, PlayerIndex.Two, out playerIndex) ||
+ IsNewKeyRelease(key, PlayerIndex.Three, out playerIndex) ||
+ IsNewKeyRelease(key, PlayerIndex.Four, out playerIndex));
+ }
+ }
+
+ ///
+ /// Helper for checking if a button was newly pressed during this update.
+ /// The controllingPlayer parameter specifies which player to read input for.
+ /// If this is null, it will accept input from any player. When a button press
+ /// is detected, the output playerIndex reports which player pressed it.
+ ///
+ public bool IsNewButtonPress(Buttons button, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
+ {
+ if (controllingPlayer.HasValue)
+ {
+ // Read input from the specified player.
+ playerIndex = controllingPlayer.Value;
+
+ int i = (int)playerIndex;
+
+ return (CurrentGamePadStates[i].IsButtonDown(button) &&
+ LastGamePadStates[i].IsButtonUp(button));
+ }
+ else
+ {
+ // Accept input from any player.
+ return (IsNewButtonPress(button, PlayerIndex.One, out playerIndex) ||
+ IsNewButtonPress(button, PlayerIndex.Two, out playerIndex) ||
+ IsNewButtonPress(button, PlayerIndex.Three, out playerIndex) ||
+ IsNewButtonPress(button, PlayerIndex.Four, out playerIndex));
+ }
+ }
+
+ public bool IsNewButtonRelease(Buttons button, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
+ {
+ if (controllingPlayer.HasValue)
+ {
+ // Read input from the specified player.
+ playerIndex = controllingPlayer.Value;
+
+ int i = (int)playerIndex;
+
+ return (CurrentGamePadStates[i].IsButtonUp(button) &&
+ LastGamePadStates[i].IsButtonDown(button));
+ }
+ else
+ {
+ // Accept input from any player.
+ return (IsNewButtonRelease(button, PlayerIndex.One, out playerIndex) ||
+ IsNewButtonRelease(button, PlayerIndex.Two, out playerIndex) ||
+ IsNewButtonRelease(button, PlayerIndex.Three, out playerIndex) ||
+ IsNewButtonRelease(button, PlayerIndex.Four, out playerIndex));
+ }
+ }
+
+ public bool IsNewVirtualButtonPress(Buttons button)
+ {
+ return (_lastVirtualState.IsButtonUp(button) &&
+ _currentVirtualState.IsButtonDown(button));
+ }
+
+ public bool IsNewVirtualButtonRelease(Buttons button)
+ {
+ return (_lastVirtualState.IsButtonDown(button) &&
+ _currentVirtualState.IsButtonUp(button));
+ }
+
+ ///
+ /// Helper for checking if a mouse button was newly pressed during this update.
+ ///
+ public bool IsNewMouseButtonPress(MouseButtons button)
+ {
+ switch (button)
+ {
+ case MouseButtons.LeftButton:
+ return (_currentMouseState.LeftButton == ButtonState.Pressed &&
+ _lastMouseState.LeftButton == ButtonState.Released);
+ case MouseButtons.RightButton:
+ return (_currentMouseState.RightButton == ButtonState.Pressed &&
+ _lastMouseState.RightButton == ButtonState.Released);
+ case MouseButtons.MiddleButton:
+ return (_currentMouseState.MiddleButton == ButtonState.Pressed &&
+ _lastMouseState.MiddleButton == ButtonState.Released);
+ case MouseButtons.ExtraButton1:
+ return (_currentMouseState.XButton1 == ButtonState.Pressed &&
+ _lastMouseState.XButton1 == ButtonState.Released);
+ case MouseButtons.ExtraButton2:
+ return (_currentMouseState.XButton2 == ButtonState.Pressed &&
+ _lastMouseState.XButton2 == ButtonState.Released);
+ default:
+ return false;
+ }
+ }
+
+ ///
+ /// Checks if the requested mouse button is released.
+ ///
+ /// The button.
+ public bool IsNewMouseButtonRelease(MouseButtons button)
+ {
+ switch (button)
+ {
+ case MouseButtons.LeftButton:
+ return (_lastMouseState.LeftButton == ButtonState.Pressed &&
+ _currentMouseState.LeftButton == ButtonState.Released);
+ case MouseButtons.RightButton:
+ return (_lastMouseState.RightButton == ButtonState.Pressed &&
+ _currentMouseState.RightButton == ButtonState.Released);
+ case MouseButtons.MiddleButton:
+ return (_lastMouseState.MiddleButton == ButtonState.Pressed &&
+ _currentMouseState.MiddleButton == ButtonState.Released);
+ case MouseButtons.ExtraButton1:
+ return (_lastMouseState.XButton1 == ButtonState.Pressed &&
+ _currentMouseState.XButton1 == ButtonState.Released);
+ case MouseButtons.ExtraButton2:
+ return (_lastMouseState.XButton2 == ButtonState.Pressed &&
+ _currentMouseState.XButton2 == ButtonState.Released);
+ default:
+ return false;
+ }
+ }
+ }
+}
diff --git a/LoadingScreen.cs b/LoadingScreen.cs
new file mode 100644
index 0000000..bd0e162
--- /dev/null
+++ b/LoadingScreen.cs
@@ -0,0 +1,163 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// LoadingScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using GameStateManagement;
+#endregion
+
+namespace GameStateManagement
+{
+ ///
+ /// The loading screen coordinates transitions between the menu system and the
+ /// game itself. Normally one screen will transition off at the same time as
+ /// the next screen is transitioning on, but for larger transitions that can
+ /// take a longer time to load their data, we want the menu system to be entirely
+ /// gone before we start loading the game. This is done as follows:
+ ///
+ /// - Tell all the existing screens to transition off.
+ /// - Activate a loading screen, which will transition on at the same time.
+ /// - The loading screen watches the state of the previous screens.
+ /// - When it sees they have finished transitioning off, it activates the real
+ /// next screen, which may take a long time to load its data. The loading
+ /// screen will be the only thing displayed while this load is taking place.
+ ///
+ class LoadingScreen : GameScreen
+ {
+ #region Fields
+
+ bool loadingIsSlow;
+ bool otherScreensAreGone;
+
+ GameScreen[] screensToLoad;
+
+ #endregion
+
+ #region Initialization
+
+
+ ///
+ /// The constructor is private: loading screens should
+ /// be activated via the static Load method instead.
+ ///
+ private LoadingScreen(ScreenManager screenManager, bool loadingIsSlow,
+ GameScreen[] screensToLoad)
+ {
+ this.loadingIsSlow = loadingIsSlow;
+ this.screensToLoad = screensToLoad;
+
+ TransitionOnTime = TimeSpan.FromSeconds(0.5);
+ }
+
+
+ ///
+ /// Activates the loading screen.
+ ///
+ public static void Load(ScreenManager screenManager, bool loadingIsSlow,
+ PlayerIndex? controllingPlayer,
+ params GameScreen[] screensToLoad)
+ {
+ // Tell all the current screens to transition off.
+ foreach (GameScreen screen in screenManager.GetScreens())
+ screen.ExitScreen();
+
+ // Create and activate the loading screen.
+ LoadingScreen loadingScreen = new LoadingScreen(screenManager,
+ loadingIsSlow,
+ screensToLoad);
+
+ screenManager.AddScreen(loadingScreen, controllingPlayer);
+ }
+
+
+ #endregion
+
+ #region Update and Draw
+
+
+ ///
+ /// Updates the loading screen.
+ ///
+ public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+ bool coveredByOtherScreen)
+ {
+ base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+ // If all the previous screens have finished transitioning
+ // off, it is time to actually perform the load.
+ if (otherScreensAreGone)
+ {
+ ScreenManager.RemoveScreen(this);
+
+ foreach (GameScreen screen in screensToLoad)
+ {
+ if (screen != null)
+ {
+ ScreenManager.AddScreen(screen, ControllingPlayer);
+ }
+ }
+
+ // Once the load has finished, we use ResetElapsedTime to tell
+ // the game timing mechanism that we have just finished a very
+ // long frame, and that it should not try to catch up.
+ ScreenManager.Game.ResetElapsedTime();
+ }
+ }
+
+
+ ///
+ /// Draws the loading screen.
+ ///
+ public override void Draw(GameTime gameTime)
+ {
+ // If we are the only active screen, that means all the previous screens
+ // must have finished transitioning off. We check for this in the Draw
+ // method, rather than in Update, because it isn't enough just for the
+ // screens to be gone: in order for the transition to look good we must
+ // have actually drawn a frame without them before we perform the load.
+ if ((ScreenState == ScreenState.Active) &&
+ (ScreenManager.GetScreens().Length == 1))
+ {
+ otherScreensAreGone = true;
+ }
+
+ // The gameplay screen takes a while to load, so we display a loading
+ // message while that is going on, but the menus load very quickly, and
+ // it would look silly if we flashed this up for just a fraction of a
+ // second while returning from the game to the menus. This parameter
+ // tells us how long the loading is going to take, so we know whether
+ // to bother drawing the message.
+ if (loadingIsSlow)
+ {
+ SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+ SpriteFont font = ScreenManager.Font;
+
+ const string message = "Loading...";
+
+ // Center the text in the viewport.
+ Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+ Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
+ Vector2 textSize = font.MeasureString(message);
+ Vector2 textPosition = (viewportSize - textSize) / 2;
+
+ Color color = Color.White * TransitionAlpha;
+
+ // Draw the text.
+ spriteBatch.Begin();
+ spriteBatch.DrawString(font, message, textPosition, color);
+ spriteBatch.End();
+ }
+ }
+
+
+ #endregion
+ }
+}
diff --git a/MainMenuScreen.cs b/MainMenuScreen.cs
new file mode 100644
index 0000000..8d6e035
--- /dev/null
+++ b/MainMenuScreen.cs
@@ -0,0 +1,99 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// MainMenuScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using Microsoft.Xna.Framework;
+using GameStateManagementSample;
+#endregion
+
+namespace GameStateManagement
+{
+ ///
+ /// The main menu screen is the first thing displayed when the game starts up.
+ ///
+ class MainMenuScreen : MenuScreen
+ {
+ #region Initialization
+
+
+ ///
+ /// Constructor fills in the menu contents.
+ ///
+ public MainMenuScreen()
+ : base("Main Menu")
+ {
+ // Create our menu entries.
+ MenuEntry playGameMenuEntry = new MenuEntry("Play Game");
+ MenuEntry optionsMenuEntry = new MenuEntry("Options");
+ MenuEntry exitMenuEntry = new MenuEntry("Exit");
+
+ // Hook up menu event handlers.
+ playGameMenuEntry.Selected += PlayGameMenuEntrySelected;
+ optionsMenuEntry.Selected += OptionsMenuEntrySelected;
+ exitMenuEntry.Selected += OnCancel;
+
+ // Add entries to the menu.
+ MenuEntries.Add(playGameMenuEntry);
+ MenuEntries.Add(optionsMenuEntry);
+ MenuEntries.Add(exitMenuEntry);
+ }
+
+
+ #endregion
+
+ #region Handle Input
+
+
+ ///
+ /// Event handler for when the Play Game menu entry is selected.
+ ///
+ void PlayGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+ {
+ LoadingScreen.Load(ScreenManager, true, e.PlayerIndex,
+ new GameplayScreen());
+ }
+
+
+ ///
+ /// Event handler for when the Options menu entry is selected.
+ ///
+ void OptionsMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+ {
+ ScreenManager.AddScreen(new OptionsMenuScreen(), e.PlayerIndex);
+ }
+
+
+ ///
+ /// When the user cancels the main menu, ask if they want to exit the sample.
+ ///
+ protected override void OnCancel(PlayerIndex playerIndex)
+ {
+ const string message = "Are you sure you want to exit this sample?";
+
+ MessageBoxScreen confirmExitMessageBox = new MessageBoxScreen(message);
+
+ confirmExitMessageBox.Accepted += ConfirmExitMessageBoxAccepted;
+
+ ScreenManager.AddScreen(confirmExitMessageBox, playerIndex);
+ }
+
+
+ ///
+ /// Event handler for when the user selects ok on the "are you sure
+ /// you want to exit" message box.
+ ///
+ void ConfirmExitMessageBoxAccepted(object sender, PlayerIndexEventArgs e)
+ {
+ ScreenManager.Game.Exit();
+ }
+
+
+ #endregion
+ }
+}
diff --git a/MenuEntry.cs b/MenuEntry.cs
new file mode 100644
index 0000000..97d2c40
--- /dev/null
+++ b/MenuEntry.cs
@@ -0,0 +1,192 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// MenuEntry.cs
+//
+// XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using GameStateManagement;
+#endregion
+
+namespace GameStateManagement
+{
+ ///
+ /// Helper class represents a single entry in a MenuScreen. By default this
+ /// just draws the entry text string, but it can be customized to display menu
+ /// entries in different ways. This also provides an event that will be raised
+ /// when the menu entry is selected.
+ ///
+ public class MenuEntry
+ {
+ #region Fields
+
+ ///
+ /// The text rendered for this entry.
+ ///
+ string text;
+
+ ///
+ /// Tracks a fading selection effect on the entry.
+ ///
+ ///
+ /// The entries transition out of the selection effect when they are deselected.
+ ///
+ float selectionFade;
+
+ ///
+ /// The position at which the entry is drawn. This is set by the MenuScreen
+ /// each frame in Update.
+ ///
+ Vector2 position;
+
+ #endregion
+
+ #region Properties
+
+
+ ///
+ /// Gets or sets the text of this menu entry.
+ ///
+ public string Text
+ {
+ get { return text; }
+ set { text = value; }
+ }
+
+
+ ///
+ /// Gets or sets the position at which to draw this menu entry.
+ ///
+ public Vector2 Position
+ {
+ get { return position; }
+ set { position = value; }
+ }
+
+
+ #endregion
+
+ #region Events
+
+
+ ///
+ /// Event raised when the menu entry is selected.
+ ///
+ public event EventHandler Selected;
+
+
+ ///
+ /// Method for raising the Selected event.
+ ///
+ protected internal virtual void OnSelectEntry(PlayerIndex playerIndex)
+ {
+ if (Selected != null)
+ Selected(this, new PlayerIndexEventArgs(playerIndex));
+ }
+
+
+ #endregion
+
+ #region Initialization
+
+
+ ///
+ /// Constructs a new menu entry with the specified text.
+ ///
+ public MenuEntry(string text)
+ {
+ this.text = text;
+ }
+
+
+ #endregion
+
+ #region Update and Draw
+
+
+ ///
+ /// Updates the menu entry.
+ ///
+ public virtual void Update(MenuScreen screen, bool isSelected, GameTime gameTime)
+ {
+ // there is no such thing as a selected item on Windows Phone, so we always
+ // force isSelected to be false
+#if WINDOWS_PHONE
+ isSelected = false;
+#endif
+
+ // When the menu selection changes, entries gradually fade between
+ // their selected and deselected appearance, rather than instantly
+ // popping to the new state.
+ float fadeSpeed = (float)gameTime.ElapsedGameTime.TotalSeconds * 4;
+
+ if (isSelected)
+ selectionFade = Math.Min(selectionFade + fadeSpeed, 1);
+ else
+ selectionFade = Math.Max(selectionFade - fadeSpeed, 0);
+ }
+
+
+ ///
+ /// Draws the menu entry. This can be overridden to customize the appearance.
+ ///
+ public virtual void Draw(MenuScreen screen, bool isSelected, GameTime gameTime)
+ {
+ // there is no such thing as a selected item on Windows Phone, so we always
+ // force isSelected to be false
+#if WINDOWS_PHONE
+ isSelected = false;
+#endif
+
+ // Draw the selected entry in yellow, otherwise white.
+ Color color = isSelected ? Color.Yellow : Color.White;
+
+ // Pulsate the size of the selected menu entry.
+ double time = gameTime.TotalGameTime.TotalSeconds;
+
+ float pulsate = (float)Math.Sin(time * 6) + 1;
+
+ float scale = 1 + pulsate * 0.05f * selectionFade;
+
+ // Modify the alpha to fade text out during transitions.
+ color *= screen.TransitionAlpha;
+
+ // Draw text, centered on the middle of each line.
+ ScreenManager screenManager = screen.ScreenManager;
+ SpriteBatch spriteBatch = screenManager.SpriteBatch;
+ SpriteFont font = screenManager.Font;
+
+ Vector2 origin = new Vector2(0, font.LineSpacing / 2);
+
+ spriteBatch.DrawString(font, text, position, color, 0,
+ origin, scale, SpriteEffects.None, 0);
+ }
+
+
+ ///
+ /// Queries how much space this menu entry requires.
+ ///
+ public virtual int GetHeight(MenuScreen screen)
+ {
+ return screen.ScreenManager.Font.LineSpacing;
+ }
+
+
+ ///
+ /// Queries how wide the entry is, used for centering on the screen.
+ ///
+ public virtual int GetWidth(MenuScreen screen)
+ {
+ return (int)screen.ScreenManager.Font.MeasureString(Text).X;
+ }
+
+
+ #endregion
+ }
+}
diff --git a/MenuScreen.cs b/MenuScreen.cs
new file mode 100644
index 0000000..8a1b061
--- /dev/null
+++ b/MenuScreen.cs
@@ -0,0 +1,329 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// MenuScreen.cs
+//
+// XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+//using Microsoft.Xna.Framework.Input.Touch;
+using Microsoft.Xna.Framework.Input;
+//using FarseerPhysics.SamplesFramework;
+#endregion
+
+namespace GameStateManagement
+{
+ ///
+ /// Base class for screens that contain a menu of options. The user can
+ /// move up and down to select an entry, or cancel to back out of the screen.
+ ///
+ public class MenuScreen : GameScreen
+ {
+ #region Fields
+
+ // the number of pixels to pad above and below menu entries for touch input
+ const int menuEntryPadding = 10;
+
+ private List menuEntries = new List();
+ int selectedEntry = 0;
+ string menuTitle;
+
+ InputAction menuUp;
+ InputAction menuDown;
+ InputAction menuSelect;
+ InputAction menuCancel;
+
+ #endregion
+
+ #region Properties
+
+
+ ///
+ /// Gets the list of menu entries, so derived classes can add
+ /// or change the menu contents.
+ ///
+ protected IList MenuEntries
+ {
+ get { return menuEntries; }
+ }
+
+
+ #endregion
+
+ #region Initialization
+
+
+ ///
+ /// Constructor.
+ ///
+ public MenuScreen(string menuTitle)
+ {
+ this.menuTitle = menuTitle;
+ // menus generally only need Tap for menu selection
+ //EnabledGestures = GestureType.Tap;
+
+ TransitionOnTime = TimeSpan.FromSeconds(0.5);
+ TransitionOffTime = TimeSpan.FromSeconds(0.5);
+
+ menuUp = new InputAction(
+ new Buttons[] { Buttons.DPadUp, Buttons.LeftThumbstickUp },
+ new Keys[] { Keys.Up },
+ true);
+ menuDown = new InputAction(
+ new Buttons[] { Buttons.DPadDown, Buttons.LeftThumbstickDown },
+ new Keys[] { Keys.Down },
+ true);
+ menuSelect = new InputAction(
+ new Buttons[] { Buttons.A, Buttons.Start },
+ new Keys[] { Keys.Enter, Keys.Space },
+ true);
+ menuCancel = new InputAction(
+ new Buttons[] { Buttons.B, Buttons.Back },
+ new Keys[] { Keys.Escape },
+ true);
+ }
+
+
+ #endregion
+
+ public void AddMenuItem(string name)
+ {
+
+ menuEntries.Add(new MenuEntry(name));
+ }
+
+ #region Handle Input
+
+ ///
+ /// Allows the screen to create the hit bounds for a particular menu entry.
+ ///
+ protected virtual Rectangle GetMenuEntryHitBounds(MenuEntry entry)
+ {
+ // the hit bounds are the entire width of the screen, and the height of the entry
+ // with some additional padding above and below.
+ return new Rectangle(
+ 0,
+ (int)entry.Position.Y - menuEntryPadding,
+ ScreenManager.GraphicsDevice.Viewport.Width,
+ entry.GetHeight(this) + (menuEntryPadding * 2));
+ }
+
+ ///
+ /// Responds to user input, changing the selected entry and accepting
+ /// or cancelling the menu.
+ ///
+ public override void HandleInput(GameTime gameTime, InputState input)
+ {
+ // For input tests we pass in our ControllingPlayer, which may
+ // either be null (to accept input from any player) or a specific index.
+ // If we pass a null controlling player, the InputState helper returns to
+ // us which player actually provided the input. We pass that through to
+ // OnSelectEntry and OnCancel, so they can tell which player triggered them.
+
+
+#if WINDOWS || XBOX360
+ PlayerIndex playerIndex;
+ // Move to the previous menu entry?
+ if (menuUp.Evaluate(input, ControllingPlayer, out playerIndex))
+ {
+ selectedEntry--;
+
+ if (selectedEntry < 0)
+ selectedEntry = menuEntries.Count - 1;
+ }
+
+ // Move to the next menu entry?
+ if (menuDown.Evaluate(input, ControllingPlayer, out playerIndex))
+ {
+ selectedEntry++;
+
+ if (selectedEntry >= menuEntries.Count)
+ selectedEntry = 0;
+ }
+
+ if (menuSelect.Evaluate(input, ControllingPlayer, out playerIndex))
+ {
+ OnSelectEntry(selectedEntry, playerIndex);
+ }
+ else if (menuCancel.Evaluate(input, ControllingPlayer, out playerIndex))
+ {
+ OnCancel(playerIndex);
+ }
+#endif
+
+#if WINDOWS_PHONE
+ //selectedEntry = 1;
+
+ PlayerIndex player;
+ if (input.IsNewButtonPress(Buttons.Back, ControllingPlayer, out player))
+ {
+ OnCancel(player);
+ }
+
+ // look for any taps that occurred and select any entries that were tapped
+ foreach (GestureSample gesture in input.Gestures)
+ {
+ //System.Diagnostics.Debugger.Break();
+ if (gesture.GestureType == GestureType.Tap)
+ {
+ // convert the position to a Point that we can test against a Rectangle
+ Point tapLocation = new Point((int)gesture.Position.X, (int)gesture.Position.Y);
+
+ // iterate the entries to see if any were tapped
+ for (int i = 0; i < menuEntries.Count; i++)
+ {
+ MenuEntry menuEntry = menuEntries[i];
+
+ if (GetMenuEntryHitBounds(menuEntry).Contains(tapLocation))
+ {
+ // select the entry. since gestures are only available on Windows Phone,
+ // we can safely pass PlayerIndex.One to all entries since there is only
+ // one player on Windows Phone.
+ OnSelectEntry(i, PlayerIndex.One);
+ }
+ }
+ }
+ }
+#endif
+ }
+
+
+ ///
+ /// Handler for when the user has chosen a menu entry.
+ ///
+ protected virtual void OnSelectEntry(int entryIndex, PlayerIndex playerIndex)
+ {
+ menuEntries[entryIndex].OnSelectEntry(playerIndex);
+ }
+
+
+ ///
+ /// Handler for when the user has cancelled the menu.
+ ///
+ protected virtual void OnCancel(PlayerIndex playerIndex)
+ {
+ ExitScreen();
+ }
+
+
+ ///
+ /// Helper overload makes it easy to use OnCancel as a MenuEntry event handler.
+ ///
+ protected void OnCancel(object sender, PlayerIndexEventArgs e)
+ {
+ OnCancel(e.PlayerIndex);
+ }
+
+
+ #endregion
+
+ #region Update and Draw
+
+
+ ///
+ /// Allows the screen the chance to position the menu entries. By default
+ /// all menu entries are lined up in a vertical list, centered on the screen.
+ ///
+ protected virtual void UpdateMenuEntryLocations()
+ {
+ // Make the menu slide into place during transitions, using a
+ // power curve to make things look more interesting (this makes
+ // the movement slow down as it nears the end).
+ float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
+
+ // start at Y = 175; each X value is generated per entry
+ Vector2 position = new Vector2(0f, 175f);
+
+ // update each menu entry's location in turn
+ for (int i = 0; i < menuEntries.Count; i++)
+ {
+ MenuEntry menuEntry = menuEntries[i];
+
+ // each entry is to be centered horizontally
+ position.X = ScreenManager.GraphicsDevice.Viewport.Width / 2 - menuEntry.GetWidth(this) / 2;
+
+ if (ScreenState == ScreenState.TransitionOn)
+ position.X -= transitionOffset * 256;
+ else
+ position.X += transitionOffset * 512;
+
+ // set the entry's position
+ menuEntry.Position = position;
+
+ // move down for the next entry the size of this entry
+ position.Y += menuEntry.GetHeight(this);
+ }
+ }
+
+
+ ///
+ /// Updates the menu.
+ ///
+ public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+ bool coveredByOtherScreen)
+ {
+ base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+ // Update each nested MenuEntry object.
+ for (int i = 0; i < menuEntries.Count; i++)
+ {
+ bool isSelected = IsActive && (i == selectedEntry);
+
+ menuEntries[i].Update(this, isSelected, gameTime);
+ }
+ }
+
+
+ ///
+ /// Draws the menu.
+ ///
+ public override void Draw(GameTime gameTime)
+ {
+ // make sure our entries are in the right place before we draw them
+ UpdateMenuEntryLocations();
+
+ GraphicsDevice graphics = ScreenManager.GraphicsDevice;
+ SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+ SpriteFont font = ScreenManager.Font;
+
+ spriteBatch.Begin();
+
+ // Draw each menu entry in turn.
+ for (int i = 0; i < menuEntries.Count; i++)
+ {
+ MenuEntry menuEntry = menuEntries[i];
+
+ bool isSelected = IsActive && (i == selectedEntry);
+
+ menuEntry.Draw(this, isSelected, gameTime);
+ }
+
+ // Make the menu slide into place during transitions, using a
+ // power curve to make things look more interesting (this makes
+ // the movement slow down as it nears the end).
+ float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
+
+ // Draw the menu title centered on the screen
+ Vector2 titlePosition = new Vector2(graphics.Viewport.Width / 2, 80);
+ Vector2 titleOrigin = font.MeasureString(menuTitle) / 2;
+ Color titleColor = new Color(192, 192, 192) * TransitionAlpha;
+ float titleScale = 1.25f;
+
+ titlePosition.Y -= transitionOffset * 100;
+
+ spriteBatch.DrawString(font, menuTitle, titlePosition, titleColor, 0,
+ titleOrigin, titleScale, SpriteEffects.None, 0);
+
+ spriteBatch.End();
+ }
+
+
+ #endregion
+ }
+}
diff --git a/MessageBoxScreen.cs b/MessageBoxScreen.cs
new file mode 100644
index 0000000..9c25ac0
--- /dev/null
+++ b/MessageBoxScreen.cs
@@ -0,0 +1,186 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// MessageBoxScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using GameStateManagement;
+#endregion
+
+namespace GameStateManagement
+{
+ ///
+ /// A popup message box screen, used to display "are you sure?"
+ /// confirmation messages.
+ ///
+ class MessageBoxScreen : GameScreen
+ {
+ #region Fields
+
+ string message;
+ Texture2D gradientTexture;
+
+ InputAction menuSelect;
+ InputAction menuCancel;
+
+ #endregion
+
+ #region Events
+
+ public event EventHandler Accepted;
+ public event EventHandler Cancelled;
+
+ #endregion
+
+ #region Initialization
+
+
+ ///
+ /// Constructor automatically includes the standard "A=ok, B=cancel"
+ /// usage text prompt.
+ ///
+ public MessageBoxScreen(string message)
+ : this(message, true)
+ { }
+
+
+ ///
+ /// Constructor lets the caller specify whether to include the standard
+ /// "A=ok, B=cancel" usage text prompt.
+ ///
+ public MessageBoxScreen(string message, bool includeUsageText)
+ {
+ const string usageText = "\nA button, Space, Enter = ok" +
+ "\nB button, Esc = cancel";
+
+ if (includeUsageText)
+ this.message = message + usageText;
+ else
+ this.message = message;
+
+ IsPopup = true;
+
+ TransitionOnTime = TimeSpan.FromSeconds(0.2);
+ TransitionOffTime = TimeSpan.FromSeconds(0.2);
+
+ menuSelect = new InputAction(
+ new Buttons[] { Buttons.A, Buttons.Start },
+ new Keys[] { Keys.Space, Keys.Enter },
+ true);
+ menuCancel = new InputAction(
+ new Buttons[] { Buttons.B, Buttons.Back },
+ new Keys[] { Keys.Escape, Keys.Back },
+ true);
+ }
+
+
+ ///
+ /// Loads graphics content for this screen. This uses the shared ContentManager
+ /// provided by the Game class, so the content will remain loaded forever.
+ /// Whenever a subsequent MessageBoxScreen tries to load this same content,
+ /// it will just get back another reference to the already loaded data.
+ ///
+ public override void Activate(bool instancePreserved)
+ {
+ if (!instancePreserved)
+ {
+ ContentManager content = ScreenManager.Game.Content;
+ gradientTexture = content.Load("gradient");
+ }
+ }
+
+
+ #endregion
+
+ #region Handle Input
+
+
+ ///
+ /// Responds to user input, accepting or cancelling the message box.
+ ///
+ public override void HandleInput(GameTime gameTime, InputState input)
+ {
+ PlayerIndex playerIndex;
+
+ // We pass in our ControllingPlayer, which may either be null (to
+ // accept input from any player) or a specific index. If we pass a null
+ // controlling player, the InputState helper returns to us which player
+ // actually provided the input. We pass that through to our Accepted and
+ // Cancelled events, so they can tell which player triggered them.
+ if (menuSelect.Evaluate(input, ControllingPlayer, out playerIndex))
+ {
+ // Raise the accepted event, then exit the message box.
+ if (Accepted != null)
+ Accepted(this, new PlayerIndexEventArgs(playerIndex));
+
+ ExitScreen();
+ }
+ else if (menuCancel.Evaluate(input, ControllingPlayer, out playerIndex))
+ {
+ // Raise the cancelled event, then exit the message box.
+ if (Cancelled != null)
+ Cancelled(this, new PlayerIndexEventArgs(playerIndex));
+
+ ExitScreen();
+ }
+ }
+
+
+ #endregion
+
+ #region Draw
+
+
+ ///
+ /// Draws the message box.
+ ///
+ public override void Draw(GameTime gameTime)
+ {
+ SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+ SpriteFont font = ScreenManager.Font;
+
+ // Darken down any other screens that were drawn beneath the popup.
+ ScreenManager.FadeBackBufferToBlack(TransitionAlpha * 2 / 3);
+
+ // Center the message text in the viewport.
+ Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+ Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
+ Vector2 textSize = font.MeasureString(message);
+ Vector2 textPosition = (viewportSize - textSize) / 2;
+
+ // The background includes a border somewhat larger than the text itself.
+ const int hPad = 32;
+ const int vPad = 16;
+
+ Rectangle backgroundRectangle = new Rectangle((int)textPosition.X - hPad,
+ (int)textPosition.Y - vPad,
+ (int)textSize.X + hPad * 2,
+ (int)textSize.Y + vPad * 2);
+
+ // Fade the popup alpha during transitions.
+ Color color = Color.White * TransitionAlpha;
+
+ spriteBatch.Begin();
+
+ // Draw the background rectangle.
+ spriteBatch.Draw(gradientTexture, backgroundRectangle, color);
+
+ // Draw the message box text.
+ spriteBatch.DrawString(font, message, textPosition, color);
+
+ spriteBatch.End();
+ }
+
+
+ #endregion
+ }
+}
diff --git a/OptionsMenuScreen.cs b/OptionsMenuScreen.cs
new file mode 100644
index 0000000..5afba98
--- /dev/null
+++ b/OptionsMenuScreen.cs
@@ -0,0 +1,149 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// OptionsMenuScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using Microsoft.Xna.Framework;
+#endregion
+
+namespace GameStateManagement
+{
+ ///
+ /// The options screen is brought up over the top of the main menu
+ /// screen, and gives the user a chance to configure the game
+ /// in various hopefully useful ways.
+ ///
+ class OptionsMenuScreen : MenuScreen
+ {
+ #region Fields
+
+ MenuEntry ungulateMenuEntry;
+ MenuEntry languageMenuEntry;
+ MenuEntry frobnicateMenuEntry;
+ MenuEntry elfMenuEntry;
+
+ enum Ungulate
+ {
+ BactrianCamel,
+ Dromedary,
+ Llama,
+ }
+
+ static Ungulate currentUngulate = Ungulate.Dromedary;
+
+ static string[] languages = { "C#", "French", "Deoxyribonucleic acid" };
+ static int currentLanguage = 0;
+
+ static bool frobnicate = true;
+
+ static int elf = 23;
+
+ #endregion
+
+ #region Initialization
+
+
+ ///
+ /// Constructor.
+ ///
+ public OptionsMenuScreen()
+ : base("Options")
+ {
+ // Create our menu entries.
+ ungulateMenuEntry = new MenuEntry(string.Empty);
+ languageMenuEntry = new MenuEntry(string.Empty);
+ frobnicateMenuEntry = new MenuEntry(string.Empty);
+ elfMenuEntry = new MenuEntry(string.Empty);
+
+ SetMenuEntryText();
+
+ MenuEntry back = new MenuEntry("Back");
+
+ // Hook up menu event handlers.
+ ungulateMenuEntry.Selected += UngulateMenuEntrySelected;
+ languageMenuEntry.Selected += LanguageMenuEntrySelected;
+ frobnicateMenuEntry.Selected += FrobnicateMenuEntrySelected;
+ elfMenuEntry.Selected += ElfMenuEntrySelected;
+ back.Selected += OnCancel;
+
+ // Add entries to the menu.
+ MenuEntries.Add(ungulateMenuEntry);
+ MenuEntries.Add(languageMenuEntry);
+ MenuEntries.Add(frobnicateMenuEntry);
+ MenuEntries.Add(elfMenuEntry);
+ MenuEntries.Add(back);
+ }
+
+
+ ///
+ /// Fills in the latest values for the options screen menu text.
+ ///
+ void SetMenuEntryText()
+ {
+ ungulateMenuEntry.Text = "Preferred ungulate: " + currentUngulate;
+ languageMenuEntry.Text = "Language: " + languages[currentLanguage];
+ frobnicateMenuEntry.Text = "Frobnicate: " + (frobnicate ? "on" : "off");
+ elfMenuEntry.Text = "elf: " + elf;
+ }
+
+
+ #endregion
+
+ #region Handle Input
+
+
+ ///
+ /// Event handler for when the Ungulate menu entry is selected.
+ ///
+ void UngulateMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+ {
+ currentUngulate++;
+
+ if (currentUngulate > Ungulate.Llama)
+ currentUngulate = 0;
+
+ SetMenuEntryText();
+ }
+
+
+ ///
+ /// Event handler for when the Language menu entry is selected.
+ ///
+ void LanguageMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+ {
+ currentLanguage = (currentLanguage + 1) % languages.Length;
+
+ SetMenuEntryText();
+ }
+
+
+ ///
+ /// Event handler for when the Frobnicate menu entry is selected.
+ ///
+ void FrobnicateMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+ {
+ frobnicate = !frobnicate;
+
+ SetMenuEntryText();
+ }
+
+
+ ///
+ /// Event handler for when the Elf menu entry is selected.
+ ///
+ void ElfMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+ {
+ elf++;
+
+ SetMenuEntryText();
+ }
+
+
+ #endregion
+ }
+}
diff --git a/PauseMenuScreen.cs b/PauseMenuScreen.cs
new file mode 100644
index 0000000..525a3f9
--- /dev/null
+++ b/PauseMenuScreen.cs
@@ -0,0 +1,79 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// PauseMenuScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using Microsoft.Xna.Framework;
+#endregion
+
+namespace GameStateManagement
+{
+ ///
+ /// The pause menu comes up over the top of the game,
+ /// giving the player options to resume or quit.
+ ///
+ class PauseMenuScreen : MenuScreen
+ {
+ #region Initialization
+
+
+ ///
+ /// Constructor.
+ ///
+ public PauseMenuScreen()
+ : base("Paused")
+ {
+ // Create our menu entries.
+ MenuEntry resumeGameMenuEntry = new MenuEntry("Resume Game");
+ MenuEntry quitGameMenuEntry = new MenuEntry("Quit Game");
+
+ // Hook up menu event handlers.
+ resumeGameMenuEntry.Selected += OnCancel;
+ quitGameMenuEntry.Selected += QuitGameMenuEntrySelected;
+
+ // Add entries to the menu.
+ MenuEntries.Add(resumeGameMenuEntry);
+ MenuEntries.Add(quitGameMenuEntry);
+ }
+
+
+ #endregion
+
+ #region Handle Input
+
+
+ ///
+ /// Event handler for when the Quit Game menu entry is selected.
+ ///
+ void QuitGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+ {
+ const string message = "Are you sure you want to quit this game?";
+
+ MessageBoxScreen confirmQuitMessageBox = new MessageBoxScreen(message);
+
+ confirmQuitMessageBox.Accepted += ConfirmQuitMessageBoxAccepted;
+
+ ScreenManager.AddScreen(confirmQuitMessageBox, ControllingPlayer);
+ }
+
+
+ ///
+ /// Event handler for when the user selects ok on the "are you sure
+ /// you want to quit" message box. This uses the loading screen to
+ /// transition from the game back to the main menu screen.
+ ///
+ void ConfirmQuitMessageBoxAccepted(object sender, PlayerIndexEventArgs e)
+ {
+ LoadingScreen.Load(ScreenManager, false, null, new BackgroundScreen(),
+ new MainMenuScreen());
+ }
+
+
+ #endregion
+ }
+}
diff --git a/PhoneMainMenuScreen.cs b/PhoneMainMenuScreen.cs
new file mode 100644
index 0000000..613781c
--- /dev/null
+++ b/PhoneMainMenuScreen.cs
@@ -0,0 +1,66 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// PhoneMainMenuScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+using System;
+using GameStateManagement;
+using GameStateManagementSample;
+using Microsoft.Xna.Framework;
+
+namespace GameStateManagement
+{
+ class PhoneMainMenuScreen : PhoneMenuScreen
+ {
+ public PhoneMainMenuScreen()
+ : base("Main Menu")
+ {
+ // Create a button to start the game
+ Button playButton = new Button("Play");
+ playButton.Tapped += playButton_Tapped;
+ MenuButtons.Add(playButton);
+
+ // Create two buttons to toggle sound effects and music. This sample just shows one way
+ // of making and using these buttons; it doesn't actually have sound effects or music
+ BooleanButton sfxButton = new BooleanButton("Sound Effects", true);
+ sfxButton.Tapped += sfxButton_Tapped;
+ MenuButtons.Add(sfxButton);
+
+ BooleanButton musicButton = new BooleanButton("Music", true);
+ musicButton.Tapped += musicButton_Tapped;
+ MenuButtons.Add(musicButton);
+ }
+
+ void playButton_Tapped(object sender, EventArgs e)
+ {
+ // When the "Play" button is tapped, we load the GameplayScreen
+ LoadingScreen.Load(ScreenManager, true, PlayerIndex.One, new GameplayScreen());
+ }
+
+ void sfxButton_Tapped(object sender, EventArgs e)
+ {
+ BooleanButton button = sender as BooleanButton;
+
+ // In a real game, you'd want to store away the value of
+ // the button to turn off sounds here. :)
+ }
+
+ void musicButton_Tapped(object sender, EventArgs e)
+ {
+ BooleanButton button = sender as BooleanButton;
+
+ // In a real game, you'd want to store away the value of
+ // the button to turn off music here. :)
+ }
+
+ protected override void OnCancel()
+ {
+ ScreenManager.Game.Exit();
+ base.OnCancel();
+ }
+ }
+}
diff --git a/PhoneMenuScreen.cs b/PhoneMenuScreen.cs
new file mode 100644
index 0000000..32e2b05
--- /dev/null
+++ b/PhoneMenuScreen.cs
@@ -0,0 +1,149 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// PhoneMenuScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+using System;
+using System.Collections.Generic;
+using GameStateManagement;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+//using Microsoft.Xna.Framework.Input.Touch;
+
+namespace GameStateManagement
+{
+ ///
+ /// Provides a basic base screen for menus on Windows Phone leveraging the Button class.
+ ///
+ class PhoneMenuScreen : GameScreen
+ {
+ List