GameScreen.cs 11 KB

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