2
0

GameScreen.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // GameScreen.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using System;
  11. using Microsoft.Xna.Framework;
  12. #endregion
  13. namespace RolePlaying
  14. {
  15. /// <summary>
  16. /// Enum describes the screen transition state.
  17. /// </summary>
  18. public enum ScreenState
  19. {
  20. TransitionOn,
  21. Active,
  22. TransitionOff,
  23. Hidden,
  24. }
  25. /// <summary>
  26. /// A screen is a single layer that has update and draw logic, and which
  27. /// can be combined with other layers to build up a complex menu system.
  28. /// For instance the main menu, the options menu, the "are you sure you
  29. /// want to quit" message box, and the main game itself are all implemented
  30. /// as screens.
  31. /// </summary>
  32. /// <remarks>
  33. /// Similar to a class found in the Game State Management sample on the
  34. /// XNA Creators Club Online website (http://creators.xna.com).
  35. /// </remarks>
  36. public abstract class GameScreen
  37. {
  38. #region Properties
  39. /// <summary>
  40. /// Normally when one screen is brought up over the top of another,
  41. /// the first screen will transition off to make room for the new
  42. /// one. This property indicates whether the screen is only a small
  43. /// popup, in which case screens underneath it do not need to bother
  44. /// transitioning off.
  45. /// </summary>
  46. public bool IsPopup
  47. {
  48. get { return isPopup; }
  49. protected set { isPopup = value; }
  50. }
  51. bool isPopup = false;
  52. /// <summary>
  53. /// Indicates how long the screen takes to
  54. /// transition on when it is activated.
  55. /// </summary>
  56. public TimeSpan TransitionOnTime
  57. {
  58. get { return transitionOnTime; }
  59. protected set { transitionOnTime = value; }
  60. }
  61. TimeSpan transitionOnTime = TimeSpan.Zero;
  62. /// <summary>
  63. /// Indicates how long the screen takes to
  64. /// transition off when it is deactivated.
  65. /// </summary>
  66. public TimeSpan TransitionOffTime
  67. {
  68. get { return transitionOffTime; }
  69. protected set { transitionOffTime = value; }
  70. }
  71. TimeSpan transitionOffTime = TimeSpan.Zero;
  72. /// <summary>
  73. /// Gets the current position of the screen transition, ranging
  74. /// from zero (fully active, no transition) to one (transitioned
  75. /// fully off to nothing).
  76. /// </summary>
  77. public float TransitionPosition
  78. {
  79. get { return transitionPosition; }
  80. protected set { transitionPosition = value; }
  81. }
  82. float transitionPosition = 1;
  83. /// <summary>
  84. /// Gets the current alpha of the screen transition, ranging
  85. /// from 255 (fully active, no transition) to 0 (transitioned
  86. /// fully off to nothing).
  87. /// </summary>
  88. public byte TransitionAlpha
  89. {
  90. get { return (byte)(255 - TransitionPosition * 255); }
  91. }
  92. /// <summary>
  93. /// Gets the current screen transition state.
  94. /// </summary>
  95. public ScreenState ScreenState
  96. {
  97. get { return screenState; }
  98. protected set { screenState = value; }
  99. }
  100. ScreenState screenState = ScreenState.TransitionOn;
  101. /// <summary>
  102. /// There are two possible reasons why a screen might be transitioning
  103. /// off. It could be temporarily going away to make room for another
  104. /// screen that is on top of it, or it could be going away for good.
  105. /// This property indicates whether the screen is exiting for real:
  106. /// if set, the screen will automatically remove itself as soon as the
  107. /// transition finishes.
  108. /// </summary>
  109. public bool IsExiting
  110. {
  111. get { return isExiting; }
  112. protected internal set
  113. {
  114. bool fireEvent = !isExiting && value;
  115. isExiting = value;
  116. if (fireEvent && (Exiting != null))
  117. {
  118. Exiting(this, EventArgs.Empty);
  119. }
  120. }
  121. }
  122. bool isExiting = false;
  123. /// <summary>
  124. /// Checks whether this screen is active and can respond to user input.
  125. /// </summary>
  126. public bool IsActive
  127. {
  128. get
  129. {
  130. return !otherScreenHasFocus &&
  131. (screenState == ScreenState.TransitionOn ||
  132. screenState == ScreenState.Active);
  133. }
  134. }
  135. bool otherScreenHasFocus;
  136. /// <summary>
  137. /// Gets the manager that this screen belongs to.
  138. /// </summary>
  139. public ScreenManager ScreenManager
  140. {
  141. get { return screenManager; }
  142. internal set { screenManager = value; }
  143. }
  144. ScreenManager screenManager;
  145. public event EventHandler Exiting;
  146. #endregion
  147. #region Initialization
  148. /// <summary>
  149. /// Load graphics content for the screen.
  150. /// </summary>
  151. public virtual void LoadContent() { }
  152. /// <summary>
  153. /// Unload content for the screen.
  154. /// </summary>
  155. public virtual void UnloadContent() { }
  156. #endregion
  157. #region Update and Draw
  158. /// <summary>
  159. /// Allows the screen to run logic, such as updating the transition position.
  160. /// Unlike HandleInput, this method is called regardless of whether the screen
  161. /// is active, hidden, or in the middle of a transition.
  162. /// </summary>
  163. public virtual void Update(GameTime gameTime, bool otherScreenHasFocus,
  164. bool coveredByOtherScreen)
  165. {
  166. this.otherScreenHasFocus = otherScreenHasFocus;
  167. if (IsExiting)
  168. {
  169. // If the screen is going away to die, it should transition off.
  170. screenState = ScreenState.TransitionOff;
  171. if (!UpdateTransition(gameTime, transitionOffTime, 1))
  172. {
  173. // When the transition finishes, remove the screen.
  174. ScreenManager.RemoveScreen(this);
  175. }
  176. }
  177. else if (coveredByOtherScreen)
  178. {
  179. // If the screen is covered by another, it should transition off.
  180. if (UpdateTransition(gameTime, transitionOffTime, 1))
  181. {
  182. // Still busy transitioning.
  183. screenState = ScreenState.TransitionOff;
  184. }
  185. else
  186. {
  187. // Transition finished!
  188. screenState = ScreenState.Hidden;
  189. }
  190. }
  191. else
  192. {
  193. // Otherwise the screen should transition on and become active.
  194. if (UpdateTransition(gameTime, transitionOnTime, -1))
  195. {
  196. // Still busy transitioning.
  197. screenState = ScreenState.TransitionOn;
  198. }
  199. else
  200. {
  201. // Transition finished!
  202. screenState = ScreenState.Active;
  203. }
  204. }
  205. }
  206. /// <summary>
  207. /// Helper for updating the screen transition position.
  208. /// </summary>
  209. bool UpdateTransition(GameTime gameTime, TimeSpan time, int direction)
  210. {
  211. // How much should we move by?
  212. float transitionDelta;
  213. if (time == TimeSpan.Zero)
  214. transitionDelta = 1;
  215. else
  216. transitionDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds /
  217. time.TotalMilliseconds);
  218. // Update the transition position.
  219. transitionPosition += transitionDelta * direction;
  220. // Did we reach the end of the transition?
  221. if ((transitionPosition <= 0) || (transitionPosition >= 1))
  222. {
  223. transitionPosition = MathHelper.Clamp(transitionPosition, 0, 1);
  224. return false;
  225. }
  226. // Otherwise we are still busy transitioning.
  227. return true;
  228. }
  229. /// <summary>
  230. /// Allows the screen to handle user input. Unlike Update, this method
  231. /// is only called when the screen is active, and not when some other
  232. /// screen has taken the focus.
  233. /// </summary>
  234. public virtual void HandleInput() { }
  235. /// <summary>
  236. /// This is called when the screen should draw itself.
  237. /// </summary>
  238. public virtual void Draw(GameTime gameTime) { }
  239. #endregion
  240. #region Public Methods
  241. /// <summary>
  242. /// Tells the screen to go away. Unlike ScreenManager.RemoveScreen, which
  243. /// instantly kills the screen, this method respects the transition timings
  244. /// and will give the screen a chance to gradually transition off.
  245. /// </summary>
  246. public void ExitScreen()
  247. {
  248. // flag that it should transition off and then exit.
  249. IsExiting = true;
  250. // If the screen has a zero transition time, remove it immediately.
  251. if (TransitionOffTime == TimeSpan.Zero)
  252. {
  253. ScreenManager.RemoveScreen(this);
  254. }
  255. }
  256. #endregion
  257. }
  258. }