/* * Util.GameScreen.cs * Authors: Adam Nabinger * Copyright (c) 2007-2008 Cornell University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; namespace Util { /// /// The root class for each minigame. A Screen is a DrawableGameComponent intended to be layed one on top of another generically. /// public abstract class GameScreen : DrawableGameComponent { #region Fields // The global directory for the loading content and file saving/loading private static readonly string globalRootDirectory; // The global directory for loading content from private static readonly string globalRootContentDirectory; // The global directory for storing any saved files private static readonly string globalRootStorageDirectory; // Directory to store any saved files within private const string storageDirectory = @"\Autism Collaborative\"; // The current content manager private VariableContentManager mContent; // The current root directory for content loading and file saving/loading private string mRootDirectory; // The input handler used for processing any input on the game screen private InputHandler mInputHandler; // The logger used for recording event codes private Logger mLogger; // List of drawable game components private List mComponents; // The frame rate display object private FrameRateDisplayComponent frameRateDisplay; // Whether or not the mouse cursor is trapped within the gamescreen private bool trap; /// /// Reference to the main game screen /// internal MainGame mGame; #endregion #region Properties /// /// Gets/Sets the frame rate display component. /// protected FrameRateDisplayComponent FrameRateDisplay { get { return frameRateDisplay; } private set { frameRateDisplay = value; } } /// /// The fully qualified path of the directory from which the game is being run. /// public static string GlobalRootDirectory { get { return globalRootDirectory; } } /// /// The fully qualified path of the main content directory. /// public static string GlobalRootContentDirectory { get { return globalRootContentDirectory; } } /// /// The fully qualifed path of the primary storage directory. /// Currently a subdirectory under My Documents. /// public static string GlobalRootStorageDirectory { get { return globalRootStorageDirectory; } } /// /// Expose access to the components associated with this game screen. /// public ICollection Components { get { return mComponents; } } /// /// The root, main game, hosting this screen. This reference should be used sparingly, only when necessary (which isn't often). /// [Obsolete("This Game reference should be used sparingly, when absolutely necessary, and absolutely not for things like 'Game.Components.Contains(x)' or 'foreach(thing in Game.Components)'. That's bad coding practice and will kill your performance.")] public new MainGame Game { get { return mGame; } } /// /// The bounds of the window the game is inside. /// public Rectangle WindowBounds { get { return mGame.Window.ClientBounds; } } /// /// Gets the Current Content.ContentManager /// public VariableContentManager Content { get { return mContent; } internal set { mContent = value; } } /// /// Gets the Current GraphicsDeviceManager /// public GraphicsDeviceManager GraphicsDeviceManager { get { return mGame.gdm; } } /// /// The directory from which the assembly containing this GameScreen was loaded. /// public string RootDirectory { get { return mRootDirectory; } internal set { mRootDirectory = value; if (Content != null) { Content.RootDirectory = mRootDirectory + MainGame.ContentSubdirectory; } } } /// /// Gets/Sets whether the mouse pointer is visible or not /// public bool IsMouseVisible { get { return mGame.IsMouseVisible; } set { mGame.IsMouseVisible = value; } } #endregion #region Creation protected GameScreen() : base(MainGame.TheGame) { } static GameScreen() { string RootLoc = Assembly.GetEntryAssembly().Location; if (RootLoc != null) { int val = RootLoc.LastIndexOf('\\'); globalRootDirectory = RootLoc.Substring(0, val); } globalRootContentDirectory = globalRootDirectory + MainGame.ContentSubdirectory; globalRootStorageDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + storageDirectory; if (!Directory.Exists(globalRootStorageDirectory)) { Directory.CreateDirectory(globalRootStorageDirectory); } } #endregion #region Initialization /// /// Base initialize call. /// public override void Initialize() { // Set the texture size allowed for the game based on this computer's hardware VariableContentManager.SetMaxResolutionToHardwareCapabilities(mGame.gdm.GraphicsDevice); // Initialization base.Initialize(); } /// /// Reinitialize will be called on the screen after a screen which was raised above it is done. /// public virtual void Reinitialize() { } #endregion #region Input Handler /// /// Get a new Input Handler. /// /// A new instance of Util.InputHandler protected InputHandler GetInputHandler() { if (mInputHandler == null) { mInputHandler = new InputHandler(mGame, UserProfileUtility.CurrentLogger); } return mInputHandler; } #endregion #region Logger /// /// Get a new Logger. /// /// The new logger protected Logger GetLogger() { if (mLogger == null) { mLogger = new Logger(UserProfileUtility.CurrentLogger); } return mLogger; } #endregion #region FPS /// /// Show the FPS of this screen with an overlay component. /// protected void ShowFPS() { if (FrameRateDisplay != null) { return; } FrameRateDisplay = new FrameRateDisplayComponent(); AddComponent(FrameRateDisplay); } /// /// Show the FPS of this screen with an overlay component. /// /// Path name for the font to use protected void ShowFPS(string fontName) { if (FrameRateDisplay != null) { return; } FrameRateDisplay = new FrameRateDisplayComponent(fontName); AddComponent(FrameRateDisplay); } #endregion #region Auto Clear /// /// Adds a clear object that renders the default color over the entire screen at the given draw order position /// /// The draw order position for when to render protected void AutoClear(int drawPosition) { Clear mClear = new Clear(); mClear.DrawOrder = drawPosition; AddComponent(mClear); } /// /// Adds a clear object that renders the choosen color over the entire screen at the given draw order position /// /// The draw order position for when to render /// The color to render protected void AutoClear(int drawPosition, Color color) { Clear mClear = new Clear(color); mClear.DrawOrder = drawPosition; AddComponent(mClear); } #endregion #region Management /// /// Dispose of this screen and all components it was using. /// /// Whether or not this is currently being disposed [DebuggerHidden] protected override void Dispose(bool disposing) { if (disposing) { if (trap) { MouseUtility.ReleaseTrap(); } if (mInputHandler != null) { mInputHandler.Dispose(); } if (mLogger != null) { mLogger.Dispose(); } if (mComponents != null) { while (mComponents.Count > 0) { mComponents[0].Dispose(); } } mContent.Unload(); mContent.Dispose(); } base.Dispose(disposing); } [Obsolete("This should never be used.")] public void PublicAddComponent(DrawableGameScreenComponent newComponent) { #if DEBUG Console.WriteLine("This should never be used."); #endif AddComponent(newComponent); } /// /// Add a drawable game screen component to the components list managed by this game screen. /// This component will automatically be initialized and loaded, and will be disposed when this screen is disposed. /// /// The new component to be added protected void AddComponent(DrawableGameScreenComponent newComponent) { if (newComponent.parent != null) { throw new ArgumentException("Component has already been added to a screen."); } newComponent.parent = this; if (mComponents == null) { mComponents = new List(); } mComponents.Add(newComponent); mGame.Components.Add(newComponent); //newComponent.Disposed += Components_ComponentRemoved; } internal void RemoveComponent(DrawableGameScreenComponent oldComponent) { if (mComponents != null) { mComponents.Remove(oldComponent); // mGame's component list is already handled by XNA } } #endregion #region Activation /// /// Activates and reveals this gamescreen and all of its components /// public virtual void Enable() { // Disable this Enabled = true; Visible = true; mInputHandler.Enable(); // Do the same for all of our components if (mComponents == null) { return; } // Go through and get them all foreach (DrawableGameScreenComponent component in mComponents) { // Disable them component.Enabled = true; component.Visible = true; } } /// /// Deactivates and hides this gamescreen and all of its components /// public virtual void Disable() { // Disable this Enabled = false; Visible = false; mInputHandler.Disable(); // Do the same for all of our components if (mComponents == null) { return; } // Go through and get them all foreach (DrawableGameScreenComponent component in mComponents) { // Disable them component.Enabled = false; component.Visible = false; } } #endregion #region Screen State /// /// Remove the screen that is on the top of the stack. /// Dispose, and UnloadContent are called. /// Then, the screen below, which is now on top again, gets Reinitialized. /// protected void Done() { mGame.PopScreen(); } /// /// Ask the game to exit, removing all screens and closing the program. /// protected void Exit() { mGame.Exit(); } #endregion #region Modifiers /// /// Add a new screen to the stack, on top of the current one. /// Sets the DrawOrder and UpdateOrder of the new Screen to place it on top of the stack. /// Then, Initialize and LoadContent will be called on the newScreen. /// Finally, the new Screen will enter into the common Update+Draw loop. /// /// The new game screen added to the top of the stack protected void Raise(GameScreen newScreen) { if (newScreen.RootDirectory == null) { newScreen.RootDirectory = RootDirectory; } mGame.PushScreen(newScreen); } /// /// Swap the current top screen, with the given one. /// /// The game screen to replace the current one protected void Swap(GameScreen newScreen) { if (newScreen.RootDirectory == null) { newScreen.RootDirectory = RootDirectory; } mGame.SwapScreen(newScreen); } #endregion #region Mouse /// /// Sets the mouse cursor to be unable to leave the game screen /// protected void TrapMouse() { trap = true; MouseUtility.AutoTrap(mGame); } /// /// Gets the mouse cursor's location in the given viewpot /// /// The location of the mouse cursor /// The viewport to check /// The mouse cursor's location in the given viewport public static Point MouseViewportLocation(Point mouseLoc, Viewport view) { Point ret = Point.Zero; ret.X = mouseLoc.X - view.X; ret.Y = mouseLoc.Y - view.Y; return ret; } #endregion } }