diff --git a/axios/Axios_WP7.csproj b/axios/Axios_WP7.csproj index 45f9c86..d5658bf 100644 --- a/axios/Axios_WP7.csproj +++ b/axios/Axios_WP7.csproj @@ -190,18 +190,32 @@ + + + + + + + + + + + + + + diff --git a/axios/Axios_Windows.csproj b/axios/Axios_Windows.csproj index 1b76ffe..2c73e8c 100644 --- a/axios/Axios_Windows.csproj +++ b/axios/Axios_Windows.csproj @@ -234,19 +234,33 @@ + + + + + + + + + + + + + + diff --git a/axios/Axios_Windows.csproj.user b/axios/Axios_Windows.csproj.user index 76fe5a5..566c009 100644 --- a/axios/Axios_Windows.csproj.user +++ b/axios/Axios_Windows.csproj.user @@ -1,6 +1,6 @@  - ProjectFiles + ShowAllFiles \ No newline at end of file diff --git a/axios/Axios_Xbox_360.csproj b/axios/Axios_Xbox_360.csproj index f15b1d4..7c073c9 100644 --- a/axios/Axios_Xbox_360.csproj +++ b/axios/Axios_Xbox_360.csproj @@ -183,18 +183,32 @@ + + + + + + + + + + + + + + diff --git a/axios/Engine/AxiosGameScreen.cs b/axios/Engine/AxiosGameScreen.cs index ece11f8..a487746 100644 --- a/axios/Engine/AxiosGameScreen.cs +++ b/axios/Engine/AxiosGameScreen.cs @@ -8,7 +8,9 @@ using Axios.Engine.UI; using FarseerPhysics.Dynamics; using FarseerPhysics.SamplesFramework; using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; +using GameStateManagement; namespace Axios.Engine { @@ -158,19 +160,16 @@ namespace Axios.Engine AxiosLog.Instance.AddLine("Memory usage after cleanup: ", LoggingFlag.DEBUG); } - public override void ExitScreen() + public override void Activate(bool instancePreserved) { - base.ExitScreen(); - - } - - public override void LoadContent() - { - base.LoadContent(); + base.Activate(instancePreserved); #if DEBUG if (!Axios.Settings.ScreenSaver) - this.DebugSpriteFont = this.ScreenManager.Content.Load(this.DebugTextFont); + { + ContentManager man = new ContentManager(ScreenManager.Game.Services, "Content"); + this.DebugSpriteFont = man.Load(this.DebugTextFont); + } #endif } diff --git a/axios/ScreenSystem/BackgroundScreen.cs b/axios/ScreenSystem/BackgroundScreen.cs index f4903a6..e3df4d5 100644 --- a/axios/ScreenSystem/BackgroundScreen.cs +++ b/axios/ScreenSystem/BackgroundScreen.cs @@ -1,24 +1,38 @@ -using System; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; +#region File Description +//----------------------------------------------------------------------------- +// BackgroundScreen.cs +// +// Microsoft XNA Community Game Platform +// Copyright (C) Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- +#endregion -namespace FarseerPhysics.SamplesFramework +#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 + class BackgroundScreen : GameScreen { - private const float LogoScreenHeightRatio = 0.25f; - private const float LogoScreenBorderRatio = 0.0375f; - private const float LogoWidthHeightRatio = 1.4f; + #region Fields + + ContentManager content; + Texture2D backgroundTexture; + + #endregion + + #region Initialization - private Texture2D _backgroundTexture; - private Rectangle _logoDestination; - //private Texture2D _logoTexture; - private Rectangle _viewport; /// /// Constructor. @@ -29,24 +43,40 @@ namespace FarseerPhysics.SamplesFramework TransitionOffTime = TimeSpan.FromSeconds(0.5); } - public override void LoadContent() + + /// + /// 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) { - //_logoTexture = ScreenManager.Content.Load("Common/logo"); - _backgroundTexture = ScreenManager.Content.Load("Common/gradient"); + if (!instancePreserved) + { + if (content == null) + content = new ContentManager(ScreenManager.Game.Services, "Content"); - Viewport viewport = ScreenManager.GraphicsDevice.Viewport; - Vector2 logoSize = new Vector2(); - logoSize.Y = viewport.Height * LogoScreenHeightRatio; - logoSize.X = logoSize.Y * LogoWidthHeightRatio; - - float border = viewport.Height * LogoScreenBorderRatio; - Vector2 logoPosition = new Vector2(viewport.Width - border - logoSize.X, - viewport.Height - border - logoSize.Y); - _logoDestination = new Rectangle((int)logoPosition.X, (int)logoPosition.Y, (int)logoSize.X, - (int)logoSize.Y); - _viewport = viewport.Bounds; + 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 @@ -55,20 +85,30 @@ namespace FarseerPhysics.SamplesFramework /// Update method wanting to transition off. /// public override void Update(GameTime gameTime, bool otherScreenHasFocus, - bool coveredByOtherScreen) + bool coveredByOtherScreen) { base.Update(gameTime, otherScreenHasFocus, false); } + /// /// Draws the background screen. /// public override void Draw(GameTime gameTime) { - ScreenManager.SpriteBatch.Begin(); - ScreenManager.SpriteBatch.Draw(_backgroundTexture, _viewport, Color.White); - //ScreenManager.SpriteBatch.Draw(_logoTexture, _logoDestination, Color.White * 0.6f); - ScreenManager.SpriteBatch.End(); + 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 } -} \ No newline at end of file +} diff --git a/axios/ScreenSystem/FramerateCounterComponent.cs b/axios/ScreenSystem/FramerateCounterComponent.cs index da8b0a0..cf8803e 100644 --- a/axios/ScreenSystem/FramerateCounterComponent.cs +++ b/axios/ScreenSystem/FramerateCounterComponent.cs @@ -1,6 +1,7 @@ using System; using System.Globalization; using Microsoft.Xna.Framework; +using GameStateManagement; namespace FarseerPhysics.SamplesFramework { diff --git a/axios/ScreenSystem/GameScreen.cs b/axios/ScreenSystem/GameScreen.cs index 68281cc..5319df2 100644 --- a/axios/ScreenSystem/GameScreen.cs +++ b/axios/ScreenSystem/GameScreen.cs @@ -1,19 +1,18 @@ #region File Description - //----------------------------------------------------------------------------- -// PlayerIndexEventArgs.cs +// GameScreen.cs // -// XNA Community Game Platform +// Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- - #endregion using System; +using System.IO; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input.Touch; -namespace FarseerPhysics.SamplesFramework +namespace GameStateManagement { /// /// Enum describes the screen transition state. @@ -26,6 +25,7 @@ namespace FarseerPhysics.SamplesFramework 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. @@ -35,23 +35,6 @@ namespace FarseerPhysics.SamplesFramework /// public abstract class GameScreen { - private GestureType _enabledGestures = GestureType.None; - private bool _otherScreenHasFocus; - - public GameScreen() - { - ScreenState = ScreenState.TransitionOn; - TransitionPosition = 1; - TransitionOffTime = TimeSpan.Zero; - TransitionOnTime = TimeSpan.Zero; - HasCursor = false; - HasVirtualStick = false; - } - - public bool HasCursor { get; set; } - - public bool HasVirtualStick { get; set; } - /// /// Normally when one screen is brought up over the top of another, /// the first screen will transition off to make room for the new @@ -59,26 +42,54 @@ namespace FarseerPhysics.SamplesFramework /// popup, in which case screens underneath it do not need to bother /// transitioning off. /// - public bool IsPopup { get; protected set; } + public bool IsPopup + { + get { return isPopup; } + protected set { isPopup = value; } + } + + bool isPopup = false; + /// /// Indicates how long the screen takes to /// transition on when it is activated. /// - public TimeSpan TransitionOnTime { get; protected set; } + 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; protected set; } + 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; protected set; } + public float TransitionPosition + { + get { return transitionPosition; } + protected set { transitionPosition = value; } + } + + float transitionPosition = 1; + /// /// Gets the current alpha of the screen transition, ranging @@ -90,10 +101,18 @@ namespace FarseerPhysics.SamplesFramework get { return 1f - TransitionPosition; } } + /// /// Gets the current screen transition state. /// - public ScreenState ScreenState { get; protected set; } + 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 @@ -103,9 +122,14 @@ namespace FarseerPhysics.SamplesFramework /// if set, the screen will automatically remove itself as soon as the /// transition finishes. /// - public bool IsExiting { get; protected internal set; } + public bool IsExiting + { + get { return isExiting; } + protected internal set { isExiting = value; } + } + + bool isExiting = false; - public bool AlwaysHasFocus = false; /// /// Checks whether this screen is active and can respond to user input. @@ -114,16 +138,43 @@ namespace FarseerPhysics.SamplesFramework { get { - return !_otherScreenHasFocus && - (ScreenState == ScreenState.TransitionOn || - ScreenState == ScreenState.Active); + return !otherScreenHasFocus && + (screenState == ScreenState.TransitionOn || + screenState == ScreenState.Active); } } + bool otherScreenHasFocus; + + /// /// Gets the manager that this screen belongs to. /// - public ScreenManager ScreenManager { get; internal set; } + 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 @@ -134,10 +185,10 @@ namespace FarseerPhysics.SamplesFramework /// public GestureType EnabledGestures { - get { return _enabledGestures; } + get { return enabledGestures; } protected set { - _enabledGestures = value; + enabledGestures = value; // the screen manager handles this during screen changes, but // if this screen is active and the gesture types are changing, @@ -149,36 +200,62 @@ namespace FarseerPhysics.SamplesFramework } } - /// - /// Load graphics content for the screen. - /// - public virtual void LoadContent() - { - } + GestureType enabledGestures = GestureType.None; /// - /// Unload content for the screen. + /// 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 virtual void UnloadContent() + 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) + public virtual void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen) { - _otherScreenHasFocus = otherScreenHasFocus; + this.otherScreenHasFocus = otherScreenHasFocus; - if (IsExiting) + if (isExiting) { // If the screen is going away to die, it should transition off. - ScreenState = ScreenState.TransitionOff; + screenState = ScreenState.TransitionOff; - if (!UpdateTransition(gameTime, TransitionOffTime, 1)) + if (!UpdateTransition(gameTime, transitionOffTime, 1)) { // When the transition finishes, remove the screen. ScreenManager.RemoveScreen(this); @@ -187,59 +264,55 @@ namespace FarseerPhysics.SamplesFramework else if (coveredByOtherScreen) { // If the screen is covered by another, it should transition off. - if (UpdateTransition(gameTime, TransitionOffTime, 1)) + if (UpdateTransition(gameTime, transitionOffTime, 1)) { // Still busy transitioning. - ScreenState = ScreenState.TransitionOff; + screenState = ScreenState.TransitionOff; } else { // Transition finished! - ScreenState = ScreenState.Hidden; + screenState = ScreenState.Hidden; } } else { // Otherwise the screen should transition on and become active. - if (UpdateTransition(gameTime, TransitionOnTime, -1)) + if (UpdateTransition(gameTime, transitionOnTime, -1)) { // Still busy transitioning. - ScreenState = ScreenState.TransitionOn; + screenState = ScreenState.TransitionOn; } else { // Transition finished! - ScreenState = ScreenState.Active; + screenState = ScreenState.Active; } } } + /// /// Helper for updating the screen transition position. /// - private bool UpdateTransition(GameTime gameTime, TimeSpan time, int direction) + bool UpdateTransition(GameTime gameTime, TimeSpan time, int direction) { // How much should we move by? float transitionDelta; if (time == TimeSpan.Zero) - { - transitionDelta = 1f; - } + transitionDelta = 1; else - { - transitionDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / - time.TotalMilliseconds); - } + transitionDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / time.TotalMilliseconds); // Update the transition position. - TransitionPosition += transitionDelta * direction; + transitionPosition += transitionDelta * direction; // Did we reach the end of the transition? - if (((direction < 0) && (TransitionPosition <= 0)) || - ((direction > 0) && (TransitionPosition >= 1))) + if (((direction < 0) && (transitionPosition <= 0)) || + ((direction > 0) && (transitionPosition >= 1))) { - TransitionPosition = MathHelper.Clamp(TransitionPosition, 0, 1); + transitionPosition = MathHelper.Clamp(transitionPosition, 0, 1); return false; } @@ -247,30 +320,29 @@ namespace FarseerPhysics.SamplesFramework 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(InputHelper input, GameTime gameTime) - { - } + public virtual void HandleInput(GameTime gameTime, InputState input) { } + /// /// This is called when the screen should draw itself. /// - public virtual void Draw(GameTime gameTime) - { - } + 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 virtual void ExitScreen() + public void ExitScreen() { - if (TransitionOffTime == TimeSpan.Zero && this.TransitionPosition == 0 && this.TransitionAlpha == 1) + if (TransitionOffTime == TimeSpan.Zero) { // If the screen has a zero transition time, remove it immediately. ScreenManager.RemoveScreen(this); @@ -278,8 +350,8 @@ namespace FarseerPhysics.SamplesFramework else { // Otherwise flag that it should transition off and then exit. - IsExiting = true; + isExiting = true; } } } -} \ No newline at end of file +} diff --git a/axios/ScreenSystem/InputHelper.cs b/axios/ScreenSystem/InputHelper.cs index c3d4e1c..0703add 100644 --- a/axios/ScreenSystem/InputHelper.cs +++ b/axios/ScreenSystem/InputHelper.cs @@ -3,6 +3,7 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input.Touch; +using GameStateManagement; namespace FarseerPhysics.SamplesFramework { diff --git a/axios/ScreenSystem/LogoScreen.cs b/axios/ScreenSystem/LogoScreen.cs index f78f3ec..27b1ed6 100644 --- a/axios/ScreenSystem/LogoScreen.cs +++ b/axios/ScreenSystem/LogoScreen.cs @@ -3,8 +3,9 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; +using FarseerPhysics.SamplesFramework; -namespace FarseerPhysics.SamplesFramework +namespace GameStateManagement { public class LogoScreen : GameScreen { @@ -29,34 +30,38 @@ namespace FarseerPhysics.SamplesFramework /// used the shared ContentManager provided by the Game class, the content /// would remain loaded forever. /// - public override void LoadContent() + public override void Activate(bool instancePreserved) { - if (_content == null) + if (!instancePreserved) { - _content = new ContentManager(ScreenManager.Game.Services, "Content"); + if (_content == null) + { + _content = new ContentManager(ScreenManager.Game.Services, "Content"); + } + + _farseerLogoTexture = _content.Load("Common/logo"); + + Viewport viewport = ScreenManager.GraphicsDevice.Viewport; + int rectHeight = (int)(viewport.Height * LogoScreenHeightRatio); + int rectWidth = (int)(rectHeight * LogoWidthHeightRatio); + int posX = viewport.Bounds.Center.X - rectWidth / 2; + int posY = viewport.Bounds.Center.Y - rectHeight / 2; + + _destination = new Rectangle(posX, posY, rectWidth, rectHeight); } - - _farseerLogoTexture = _content.Load("Common/logo"); - - Viewport viewport = ScreenManager.GraphicsDevice.Viewport; - int rectHeight = (int)(viewport.Height * LogoScreenHeightRatio); - int rectWidth = (int)(rectHeight * LogoWidthHeightRatio); - int posX = viewport.Bounds.Center.X - rectWidth / 2; - int posY = viewport.Bounds.Center.Y - rectHeight / 2; - - _destination = new Rectangle(posX, posY, rectWidth, rectHeight); } /// /// Unloads graphics content for this screen. /// - public override void UnloadContent() + public override void Unload() { _content.Unload(); } - public override void HandleInput(InputHelper input, GameTime gameTime) + public override void HandleInput(GameTime gameTime, InputState input) { + //input. if (input.KeyboardState.GetPressedKeys().Length > 0 || input.GamePadState.IsButtonDown(Buttons.A | Buttons.Start | Buttons.Back) || input.MouseState.LeftButton == ButtonState.Pressed) diff --git a/axios/ScreenSystem/MenuButton.cs b/axios/ScreenSystem/MenuButton.cs index 67e8df4..01d5bbe 100644 --- a/axios/ScreenSystem/MenuButton.cs +++ b/axios/ScreenSystem/MenuButton.cs @@ -2,7 +2,7 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -namespace FarseerPhysics.SamplesFramework +namespace GameStateManagement { /// /// Helper class represents a single entry in a MenuScreen. By default this diff --git a/axios/ScreenSystem/MenuEntry.cs b/axios/ScreenSystem/MenuEntry.cs index 1f3efc2..6261fc1 100644 --- a/axios/ScreenSystem/MenuEntry.cs +++ b/axios/ScreenSystem/MenuEntry.cs @@ -1,39 +1,35 @@ -using System; +#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 FarseerPhysics.SamplesFramework +namespace GameStateManagement { - public enum EntryType - { - Screen, - Separator, - ExitItem, - BackItem - } - /// /// 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 sealed class MenuEntry + class MenuEntry { - private float _alpha; - private Vector2 _baseOrigin; - - private float _height; - private MenuScreen _menu; + #region Fields /// - /// The position at which the entry is drawn. This is set by the MenuScreen - /// each frame in Update. + /// The text rendered for this entry. /// - private Vector2 _position; - - private float _scale; - private GameScreen _screen; + string text; /// /// Tracks a fading selection effect on the entry. @@ -41,28 +37,17 @@ namespace FarseerPhysics.SamplesFramework /// /// The entries transition out of the selection effect when they are deselected. /// - private float _selectionFade; + float selectionFade; /// - /// The text rendered for this entry. + /// The position at which the entry is drawn. This is set by the MenuScreen + /// each frame in Update. /// - private string _text; + Vector2 position; - private EntryType _type; - private float _width; + #endregion - /// - /// Constructs a new menu entry with the specified text. - /// - public MenuEntry(MenuScreen menu, string text, EntryType type, GameScreen screen) - { - _text = text; - _screen = screen; - _type = type; - _menu = menu; - _scale = 0.9f; - _alpha = 1.0f; - } + #region Properties /// @@ -70,124 +55,138 @@ namespace FarseerPhysics.SamplesFramework /// public string Text { - get { return _text; } - set { _text = value; } + 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; } + get { return position; } + set { position = value; } } - public float Alpha + + #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) { - get { return _alpha; } - set { _alpha = value; } + if (Selected != null) + Selected(this, new PlayerIndexEventArgs(playerIndex)); } - public GameScreen Screen + + #endregion + + #region Initialization + + + /// + /// Constructs a new menu entry with the specified text. + /// + public MenuEntry(string text) { - get { return _screen; } + this.text = text; } - public void Initialize() - { - SpriteFont font = _menu.ScreenManager.Fonts.MenuSpriteFont; - _baseOrigin = new Vector2(font.MeasureString(Text).X, font.MeasureString("M").Y) * 0.5f; + #endregion - _width = font.MeasureString(Text).X * 0.8f; - _height = font.MeasureString("M").Y * 0.8f; - } + #region Update and Draw - public bool IsExitItem() - { - return _type == EntryType.ExitItem; - } - - public bool IsSelectable() - { - return _type != EntryType.Separator; - } - - public bool IsBackItem() - { - return _type == EntryType.BackItem; - } /// /// Updates the menu entry. /// - public void Update(bool isSelected, GameTime gameTime) + 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. - if (_type != EntryType.Separator) - { - float fadeSpeed = (float)gameTime.ElapsedGameTime.TotalSeconds * 4; - if (isSelected) - { - _selectionFade = Math.Min(_selectionFade + fadeSpeed, 1f); - } - else - { - _selectionFade = Math.Max(_selectionFade - fadeSpeed, 0f); - } - _scale = 0.7f + 0.1f * _selectionFade; - } + 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 void Draw() + public virtual void Draw(MenuScreen screen, bool isSelected, GameTime gameTime) { - SpriteFont font = _menu.ScreenManager.Fonts.MenuSpriteFont; - SpriteBatch batch = _menu.ScreenManager.SpriteBatch; + // 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 - Color color; - if (_type == EntryType.Separator) - { - color = Color.DarkOrange; - } - else - { - // Draw the selected entry in yellow, otherwise white - color = Color.Lerp(Color.White, new Color(255, 210, 0), _selectionFade); - } - color *= _alpha; + // 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. - batch.DrawString(font, _text, _position - _baseOrigin * _scale + Vector2.One, - Color.DarkSlateGray * _alpha * _alpha, 0, Vector2.Zero, _scale, SpriteEffects.None, 0); - batch.DrawString(font, _text, _position - _baseOrigin * _scale, color, 0, Vector2.Zero, _scale, - SpriteEffects.None, 0); + 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 int GetHeight() + public virtual int GetHeight(MenuScreen screen) { - return (int)_height; + return screen.ScreenManager.Font.LineSpacing; } + /// /// Queries how wide the entry is, used for centering on the screen. /// - public int GetWidth() + public virtual int GetWidth(MenuScreen screen) { - return (int)_width; + return (int)screen.ScreenManager.Font.MeasureString(Text).X; } + + + #endregion } -} \ No newline at end of file +} diff --git a/axios/ScreenSystem/MenuScreen.cs b/axios/ScreenSystem/MenuScreen.cs index 2b649d6..b7fe332 100644 --- a/axios/ScreenSystem/MenuScreen.cs +++ b/axios/ScreenSystem/MenuScreen.cs @@ -1,235 +1,169 @@ +#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 FarseerPhysics.SamplesFramework +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 + abstract class MenuScreen : GameScreen { -#if WINDOWS || XBOX - protected const float NumEntries = 15; -#elif WINDOWS_PHONE - protected const float NumEntries = 9; -#endif - protected List _menuEntries = new List(); - protected string _menuTitle; - protected Vector2 _titlePosition; - protected Vector2 _titleOrigin; - protected int _selectedEntry; - protected float _menuBorderTop; - protected float _menuBorderBottom; - protected float _menuBorderMargin; - protected float _menuOffset; - protected float _maxOffset; + #region Fields - protected Texture2D _texScrollButton; - protected Texture2D _texSlider; + 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 - protected MenuButton _scrollUp; - protected MenuButton _scrollDown; - protected MenuButton _scrollSlider; - protected bool _scrollLock; /// /// Constructor. /// public MenuScreen(string menuTitle) { - _menuTitle = menuTitle; + this.menuTitle = menuTitle; - TransitionOnTime = TimeSpan.FromSeconds(0.7); - TransitionOffTime = TimeSpan.FromSeconds(0.7); - HasCursor = true; + 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); } - public void AddMenuItem(string name, EntryType type, GameScreen screen) - { - MenuEntry entry = new MenuEntry(this, name, type, screen); - _menuEntries.Add(entry); - } - public void AddMenuItem(MenuEntry me) - { - _menuEntries.Add(me); - } + #endregion - public override void LoadContent() - { - base.LoadContent(); - - _texScrollButton = ScreenManager.Content.Load("Common/arrow"); - _texSlider = ScreenManager.Content.Load("Common/slider"); + #region Handle Input - //Viewport viewport = ScreenManager.GraphicsDevice.Viewport; - //float scrollBarPos = viewport.Width / 2f; - //scrollBarPos -= _texScrollButton.Width + 2f; - - - - InitMenu(); - - - - } - - public void InitMenu() - { - Viewport viewport = ScreenManager.GraphicsDevice.Viewport; - SpriteFont font = ScreenManager.Fonts.MenuSpriteFont; - float scrollBarPos = viewport.Width / 2f; - - for (int i = 0; i < _menuEntries.Count; ++i) - { - _menuEntries[i].Initialize(); - scrollBarPos = Math.Min(scrollBarPos, - (viewport.Width - _menuEntries[i].GetWidth()) / 2f); - } - - _titleOrigin = font.MeasureString(_menuTitle) / 2f; - _titlePosition = new Vector2(viewport.Width / 2f, font.MeasureString("M").Y / 2f + 10f); - - _menuBorderMargin = font.MeasureString("M").Y * 0.8f; - _menuBorderTop = (viewport.Height - _menuBorderMargin * (NumEntries - 1)) / 2f; - _menuBorderBottom = (viewport.Height + _menuBorderMargin * (NumEntries - 1)) / 2f; - - _menuOffset = 0f; - _maxOffset = Math.Max(0f, (_menuEntries.Count - NumEntries) * _menuBorderMargin); - - _scrollUp = new MenuButton(_texScrollButton, false, - new Vector2(scrollBarPos, _menuBorderTop - _texScrollButton.Height), this); - _scrollDown = new MenuButton(_texScrollButton, true, - new Vector2(scrollBarPos, _menuBorderBottom + _texScrollButton.Height), this); - _scrollSlider = new MenuButton(_texSlider, false, new Vector2(scrollBarPos, _menuBorderTop), this); - - _scrollLock = false; - } - - /// - /// Returns the index of the menu entry at the position of the given mouse state. - /// - /// Index of menu entry if valid, -1 otherwise - private int GetMenuEntryAt(Vector2 position) - { - if (this.TransitionPosition == 0f && this.ScreenState == SamplesFramework.ScreenState.Active) - { - int index = 0; - foreach (MenuEntry entry in _menuEntries) - { - float width = entry.GetWidth(); - float height = entry.GetHeight(); - Rectangle rect = new Rectangle((int)(entry.Position.X - width / 2f), - (int)(entry.Position.Y - height / 2f), - (int)width, (int)height); - if (rect.Contains((int)position.X, (int)position.Y) && entry.Alpha > 0.1f) - { - return index; - } - ++index; - } - } - return -1; - } /// /// Responds to user input, changing the selected entry and accepting /// or cancelling the menu. /// - public override void HandleInput(InputHelper input, GameTime gameTime) + public override void HandleInput(GameTime gameTime, InputState input) { - // Mouse or touch on a menu item - int hoverIndex = GetMenuEntryAt(input.Cursor); - if (hoverIndex > -1 && _menuEntries[hoverIndex].IsSelectable() && !_scrollLock) + // 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. + PlayerIndex playerIndex; + + // Move to the previous menu entry? + if (menuUp.Evaluate(input, ControllingPlayer, out playerIndex)) { - _selectedEntry = hoverIndex; - } - else - { - _selectedEntry = -1; + selectedEntry--; + + if (selectedEntry < 0) + selectedEntry = menuEntries.Count - 1; } - _scrollSlider.Hover = false; - if (input.IsCursorValid) + // Move to the next menu entry? + if (menuDown.Evaluate(input, ControllingPlayer, out playerIndex)) { - _scrollUp.Collide(input.Cursor); - _scrollDown.Collide(input.Cursor); - _scrollSlider.Collide(input.Cursor); - } - else - { - _scrollUp.Hover = false; - _scrollDown.Hover = false; - _scrollLock = false; + selectedEntry++; + + if (selectedEntry >= menuEntries.Count) + selectedEntry = 0; } - // Accept or cancel the menu? - if (input.IsMenuSelect() && _selectedEntry != -1) + if (menuSelect.Evaluate(input, ControllingPlayer, out playerIndex)) { - if (_menuEntries[_selectedEntry].IsExitItem()) - { - ScreenManager.Game.Exit(); - } - else if (_menuEntries[_selectedEntry].IsBackItem()) - { - this.ExitScreen(); - } - else if (_menuEntries[_selectedEntry].Screen != null) - { - ScreenManager.AddScreen(_menuEntries[_selectedEntry].Screen); - if (_menuEntries[_selectedEntry].Screen is IDemoScreen) - { - ScreenManager.AddScreen( - new MessageBoxScreen((_menuEntries[_selectedEntry].Screen as IDemoScreen).GetDetails())); - } - } + OnSelectEntry(selectedEntry, playerIndex); } - else if (input.IsMenuCancel()) + else if (menuCancel.Evaluate(input, ControllingPlayer, out playerIndex)) { - if (this.ScreenState == SamplesFramework.ScreenState.Active && this.TransitionPosition == 0 && this.TransitionAlpha == 1) - { - //GameScreen[] screens = ScreenManager.GetScreens(); - //if (screens[screens.Length - 1] is BackgroundScreen ||| screens.Length ) - // ScreenManager.Game.Exit(); - //if (ScreenManager.GetScreens().Length == 2) - // ScreenManager.Game.Exit(); - //else - this.ExitScreen(); - } - //ScreenManager.Game.Exit(); - } - - if (input.IsMenuPressed()) - { - if (_scrollUp.Hover) - { - _menuOffset = Math.Max(_menuOffset - 200f * (float)gameTime.ElapsedGameTime.TotalSeconds, 0f); - _scrollLock = false; - } - if (_scrollDown.Hover) - { - _menuOffset = Math.Min(_menuOffset + 200f * (float)gameTime.ElapsedGameTime.TotalSeconds, _maxOffset); - _scrollLock = false; - } - if (_scrollSlider.Hover) - { - _scrollLock = true; - } - } - if (input.IsMenuReleased()) - { - _scrollLock = false; - } - if (_scrollLock) - { - _scrollSlider.Hover = true; - _menuOffset = Math.Max(Math.Min(((input.Cursor.Y - _menuBorderTop) / (_menuBorderBottom - _menuBorderTop)) * _maxOffset, _maxOffset), 0f); + OnCancel(playerIndex); } } + + /// + /// 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. @@ -241,69 +175,49 @@ namespace FarseerPhysics.SamplesFramework // the movement slow down as it nears the end). float transitionOffset = (float)Math.Pow(TransitionPosition, 2); - Vector2 position = Vector2.Zero; - position.Y = _menuBorderTop - _menuOffset; + // 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) + for (int i = 0; i < menuEntries.Count; i++) { - position.X = ScreenManager.GraphicsDevice.Viewport.Width / 2f; + 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 * 256; - } + position.X += transitionOffset * 512; // set the entry's position - _menuEntries[i].Position = position; - - if (position.Y < _menuBorderTop) - { - _menuEntries[i].Alpha = 1f - - Math.Min(_menuBorderTop - position.Y, _menuBorderMargin) / _menuBorderMargin; - } - else if (position.Y > _menuBorderBottom) - { - _menuEntries[i].Alpha = 1f - - Math.Min(position.Y - _menuBorderBottom, _menuBorderMargin) / - _menuBorderMargin; - } - else - { - _menuEntries[i].Alpha = 1f; - } + menuEntry.Position = position; // move down for the next entry the size of this entry - position.Y += _menuEntries[i].GetHeight(); + position.Y += menuEntry.GetHeight(this); } - Vector2 scrollPos = _scrollSlider.Position; - scrollPos.Y = MathHelper.Lerp(_menuBorderTop, _menuBorderBottom, _menuOffset / _maxOffset); - _scrollSlider.Position = scrollPos; } + /// /// Updates the menu. /// public override void Update(GameTime gameTime, bool otherScreenHasFocus, - bool coveredByOtherScreen) + bool coveredByOtherScreen) { base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen); // Update each nested MenuEntry object. - for (int i = 0; i < _menuEntries.Count; ++i) + for (int i = 0; i < menuEntries.Count; i++) { - bool isSelected = IsActive && (i == _selectedEntry); - _menuEntries[i].Update(isSelected, gameTime); - } + bool isSelected = IsActive && (i == selectedEntry); - _scrollUp.Update(gameTime); - _scrollDown.Update(gameTime); - _scrollSlider.Update(gameTime); + menuEntries[i].Update(this, isSelected, gameTime); + } } + /// /// Draws the menu. /// @@ -312,30 +226,42 @@ namespace FarseerPhysics.SamplesFramework // 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.Fonts.MenuSpriteFont; + SpriteFont font = ScreenManager.Font; spriteBatch.Begin(); + // Draw each menu entry in turn. - for (int i = 0; i < _menuEntries.Count; ++i) + for (int i = 0; i < menuEntries.Count; i++) { - bool isSelected = IsActive && (i == _selectedEntry); - _menuEntries[i].Draw(); + 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). - Vector2 transitionOffset = new Vector2(0f, (float)Math.Pow(TransitionPosition, 2) * 100f); + 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.DrawString(font, _menuTitle, _titlePosition - transitionOffset + Vector2.One * 2f, Color.Black, 0, - _titleOrigin, 1f, SpriteEffects.None, 0); - spriteBatch.DrawString(font, _menuTitle, _titlePosition - transitionOffset, new Color(255, 210, 0), 0, - _titleOrigin, 1f, SpriteEffects.None, 0); - _scrollUp.Draw(); - _scrollSlider.Draw(); - _scrollDown.Draw(); spriteBatch.End(); } + + + #endregion } -} \ No newline at end of file +} diff --git a/axios/ScreenSystem/MessageBoxScreen.cs b/axios/ScreenSystem/MessageBoxScreen.cs index d3c9826..55b7a93 100644 --- a/axios/ScreenSystem/MessageBoxScreen.cs +++ b/axios/ScreenSystem/MessageBoxScreen.cs @@ -1,36 +1,87 @@ -using System; +#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 FarseerPhysics.SamplesFramework +namespace GameStateManagement { /// /// A popup message box screen, used to display "are you sure?" /// confirmation messages. /// - public class MessageBoxScreen : GameScreen + class MessageBoxScreen : GameScreen { - protected Rectangle _backgroundRectangle; - protected Texture2D _gradientTexture; - protected string _message; - protected Vector2 _textPosition; + #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) { - _message = message; + const string usageText = "\nA button, Space, Enter = ok" + + "\nB button, Esc = cancel"; + + if (includeUsageText) + this.message = message + usageText; + else + this.message = message; IsPopup = true; - HasCursor = true; - TransitionOnTime = TimeSpan.FromSeconds(0.4); - TransitionOffTime = TimeSpan.FromSeconds(0.4); + 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); } - public MessageBoxScreen() - { - IsPopup = true; - } /// /// Loads graphics content for this screen. This uses the shared ContentManager @@ -38,62 +89,98 @@ namespace FarseerPhysics.SamplesFramework /// 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 LoadContent() + public override void Activate(bool instancePreserved) { - SpriteFont font = ScreenManager.Fonts.DetailsFont; - ContentManager content = ScreenManager.Game.Content; - _gradientTexture = content.Load("Common/popup"); - - // 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); - _textPosition = (viewportSize - textSize) / 2; - - // The background includes a border somewhat larger than the text itself. - const int hPad = 32; - const int vPad = 16; - - _backgroundRectangle = new Rectangle((int)_textPosition.X - hPad, - (int)_textPosition.Y - vPad, - (int)textSize.X + hPad * 2, - (int)textSize.Y + vPad * 2); + 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(InputHelper input, GameTime gameTime) + public override void HandleInput(GameTime gameTime, InputState input) { + PlayerIndex playerIndex; - if (input.IsMenuSelect() || input.IsMenuCancel() || - input.IsNewMouseButtonPress(MouseButtons.LeftButton)) + // 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.Fonts.DetailsFont; + 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 * (2f / 3f); + Color color = Color.White * TransitionAlpha; spriteBatch.Begin(); // Draw the background rectangle. - spriteBatch.Draw(_gradientTexture, _backgroundRectangle, color); + spriteBatch.Draw(gradientTexture, backgroundRectangle, color); // Draw the message box text. - spriteBatch.DrawString(font, _message, _textPosition + Vector2.One, Color.Black); - spriteBatch.DrawString(font, _message, _textPosition, Color.White); + spriteBatch.DrawString(font, message, textPosition, color); spriteBatch.End(); } + + + #endregion } -} \ No newline at end of file +} diff --git a/axios/ScreenSystem/PhysicsGameScreen.cs b/axios/ScreenSystem/PhysicsGameScreen.cs index 30fc9f0..fafc036 100644 --- a/axios/ScreenSystem/PhysicsGameScreen.cs +++ b/axios/ScreenSystem/PhysicsGameScreen.cs @@ -6,9 +6,10 @@ using FarseerPhysics.Dynamics.Joints; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Input; +using FarseerPhysics.SamplesFramework; using Axios.Engine; -namespace FarseerPhysics.SamplesFramework +namespace GameStateManagement { public class PhysicsGameScreen : GameScreen { @@ -47,48 +48,51 @@ namespace FarseerPhysics.SamplesFramework _agentTorque = torque; } - - public override void LoadContent() + + public override void Activate(bool instancePreserved) { - base.LoadContent(); - - //We enable diagnostics to show get values for our performance counters. - Settings.EnableDiagnostics = true; - - if (World == null) + if (!instancePreserved) { - World = new World(Vector2.Zero); - } - else - { - World.Clear(); - } + base.Activate(instancePreserved); - if (DebugView == null) - { - if (!Axios.Settings.ScreenSaver) + //We enable diagnostics to show get values for our performance counters. + Settings.EnableDiagnostics = true; + + if (World == null) { - DebugView = new DebugViewXNA(World); - DebugView.RemoveFlags(DebugViewFlags.Shape); - DebugView.RemoveFlags(DebugViewFlags.Joint); - DebugView.DefaultShapeColor = Color.White; - DebugView.SleepingShapeColor = Color.LightGray; - DebugView.LoadContent(ScreenManager.GraphicsDevice, ScreenManager.Content); + World = new World(Vector2.Zero); + } + else + { + World.Clear(); } - } - if (Camera == null) - { - Camera = new Camera2D(ScreenManager.GraphicsDevice); - } - else - { - Camera.ResetCamera(); - } + if (DebugView == null) + { + if (!Axios.Settings.ScreenSaver) + { + DebugView = new DebugViewXNA(World); + DebugView.RemoveFlags(DebugViewFlags.Shape); + DebugView.RemoveFlags(DebugViewFlags.Joint); + DebugView.DefaultShapeColor = Color.White; + DebugView.SleepingShapeColor = Color.LightGray; + DebugView.LoadContent(ScreenManager.GraphicsDevice, ScreenManager.Content); + } + } - // Loading may take a while... so prevent the game from "catching up" once we finished loading - ScreenManager.Game.ResetElapsedTime(); + if (Camera == null) + { + Camera = new Camera2D(ScreenManager.GraphicsDevice); + } + else + { + Camera.ResetCamera(); + } + + // Loading may take a while... so prevent the game from "catching up" once we finished loading + ScreenManager.Game.ResetElapsedTime(); + } } public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen) @@ -110,12 +114,13 @@ namespace FarseerPhysics.SamplesFramework { } - public override void HandleInput(InputHelper input, GameTime gameTime) + public override void HandleInput(GameTime gameTime, InputState input) { #if DEBUG // Control debug view - if (input.IsNewButtonPress(Buttons.Start)) + PlayerIndex player; + if (input.IsNewButtonPress(Buttons.Start, ControllingPlayer.Value, out player)) { EnableOrDisableFlag(DebugViewFlags.Shape); EnableOrDisableFlag(DebugViewFlags.DebugPanel); @@ -126,37 +131,37 @@ namespace FarseerPhysics.SamplesFramework EnableOrDisableFlag(DebugViewFlags.Controllers); } - if (input.IsNewKeyPress(Keys.F1)) + if (input.IsNewKeyPress(Keys.F1, ControllingPlayer.Value, out player)) { EnableOrDisableFlag(DebugViewFlags.Shape); } - if (input.IsNewKeyPress(Keys.F2)) + if (input.IsNewKeyPress(Keys.F2, ControllingPlayer.Value, out player)) { EnableOrDisableFlag(DebugViewFlags.DebugPanel); EnableOrDisableFlag(DebugViewFlags.PerformanceGraph); } - if (input.IsNewKeyPress(Keys.F3)) + if (input.IsNewKeyPress(Keys.F3, ControllingPlayer.Value, out player)) { EnableOrDisableFlag(DebugViewFlags.Joint); } - if (input.IsNewKeyPress(Keys.F4)) + if (input.IsNewKeyPress(Keys.F4, ControllingPlayer.Value, out player)) { EnableOrDisableFlag(DebugViewFlags.ContactPoints); EnableOrDisableFlag(DebugViewFlags.ContactNormals); } - if (input.IsNewKeyPress(Keys.F5)) + if (input.IsNewKeyPress(Keys.F5, ControllingPlayer.Value, out player)) { EnableOrDisableFlag(DebugViewFlags.PolygonPoints); } - if (input.IsNewKeyPress(Keys.F6)) + if (input.IsNewKeyPress(Keys.F6, ControllingPlayer.Value, out player)) { EnableOrDisableFlag(DebugViewFlags.Controllers); } - if (input.IsNewKeyPress(Keys.F7)) + if (input.IsNewKeyPress(Keys.F7, ControllingPlayer.Value, out player)) { EnableOrDisableFlag(DebugViewFlags.CenterOfMass); } - if (input.IsNewKeyPress(Keys.F8)) + if (input.IsNewKeyPress(Keys.F8, ControllingPlayer.Value, out player)) { EnableOrDisableFlag(DebugViewFlags.AABB); } @@ -181,7 +186,7 @@ namespace FarseerPhysics.SamplesFramework if (input.IsNewButtonPress(Buttons.Back) || input.IsNewKeyPress(Keys.Escape)) { - if (this.ScreenState == SamplesFramework.ScreenState.Active && this.TransitionPosition == 0 && this.TransitionAlpha == 1) + if (this.ScreenState == GameStateManagement.ScreenState.Active && this.TransitionPosition == 0 && this.TransitionAlpha == 1) { //Give the screens a chance to transition CleanUp(); @@ -191,9 +196,10 @@ namespace FarseerPhysics.SamplesFramework } base.HandleInput(input, gameTime); } - - public virtual void HandleCursor(InputHelper input) + + public virtual void HandleCursor(InputState input) { + PlayerIndex player; Vector2 position = Camera.ConvertScreenToWorld(input.Cursor); if ((input.IsNewButtonPress(Buttons.A) || @@ -211,8 +217,9 @@ namespace FarseerPhysics.SamplesFramework } } - if ((input.IsNewButtonRelease(Buttons.A) || - input.IsNewMouseButtonRelease(MouseButtons.LeftButton)) && + + if ((input.IsNewButtonRelease(Buttons.A, ControllingPlayer.Value, out player) || + input.IsNewMouseButtonRelease(MouseButtons.LeftButton, ControllingPlayer.Value, out player)) && _fixedMouseJoint != null) { World.RemoveJoint(_fixedMouseJoint); diff --git a/axios/ScreenSystem/ScreenManagerComponent.cs b/axios/ScreenSystem/ScreenManagerComponent.cs index 2705ce0..7303f72 100644 --- a/axios/ScreenSystem/ScreenManagerComponent.cs +++ b/axios/ScreenSystem/ScreenManagerComponent.cs @@ -3,9 +3,11 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input.Touch; +using FarseerPhysics.SamplesFramework; -namespace FarseerPhysics.SamplesFramework +namespace GameStateManagement { + /* /// /// The screen manager is a component which manages one or more GameScreen /// instances. It maintains a stack of screens, calls their Update and Draw @@ -299,5 +301,5 @@ namespace FarseerPhysics.SamplesFramework { return _screens.ToArray(); } - } + }*/ } \ No newline at end of file