PageRenderTime 181ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Rollout Engine/Screens/Screen.cs

https://github.com/DJSymBiotiX/BType2
C# | 331 lines | 198 code | 49 blank | 84 comment | 23 complexity | fa162e0a74f0800877d2af47ef3d8be8 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Microsoft.Xna.Framework;
  5. using Microsoft.Xna.Framework.Graphics;
  6. using Rollout.Collision;
  7. using Rollout.Core;
  8. using Rollout.Core.GameObject;
  9. using Rollout.Input;
  10. using Rollout.Screens.Transitions;
  11. using Rollout.Scripting;
  12. using Rollout.Utility;
  13. namespace Rollout.Screens
  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. public abstract class Screen : DrawableGameObject
  33. {
  34. #region Properties
  35. public Transition Transition { get; set; }
  36. public string ID { get; set; }
  37. public List<Screen> Components { get; internal set; }
  38. private List<Screen> componentsToUpdate;
  39. /// <summary>
  40. /// Gets the manager that this screen belongs to.
  41. /// </summary>
  42. public Screen ComponentManager { get; internal set; }
  43. /// <summary>
  44. /// Normally when one screen is brought up over the top of another,
  45. /// the first screen will transition off to make room for the new
  46. /// one. This property indicates whether the screen is only a small
  47. /// popup, in which case screens underneath it do not need to bother
  48. /// transitioning off.
  49. /// </summary>
  50. public bool IsPopup { get; set; }
  51. public bool IsPersistant { get; set; }
  52. /// <summary>
  53. /// Gets the current screen transition state.
  54. /// </summary>
  55. public ScreenState ScreenState { get; protected set; }
  56. /// <summary>
  57. /// There are two possible reasons why a screen might be transitioning
  58. /// off. It could be temporarily going away to make room for another
  59. /// screen that is on top of it, or it could be going away for good.
  60. /// This property indicates whether the screen is exiting for real:
  61. /// if set, the screen will automatically remove itself as soon as the
  62. /// transition finishes.
  63. /// </summary>
  64. public bool IsExiting { get; protected internal set; }
  65. /// <summary>
  66. /// Checks whether this screen is active and can respond to user input.
  67. /// </summary>
  68. public bool IsActive
  69. {
  70. get
  71. {
  72. return !HasFocus &&
  73. (ScreenState == ScreenState.TransitionOn ||
  74. ScreenState == ScreenState.Active);
  75. }
  76. }
  77. bool HasFocus;
  78. #endregion
  79. #region Initialization
  80. public Screen()
  81. {
  82. ScreenContext.SetContext(this);
  83. Components = new List<Screen>();
  84. componentsToUpdate = new List<Screen>();
  85. Transition = new Transition
  86. {
  87. OnTime = Time.s(1),
  88. OffTime = Time.s(1),
  89. Position = 0
  90. };
  91. ScreenState = ScreenState.TransitionOn;
  92. IsExiting = false;
  93. IsPopup = false;
  94. }
  95. /// <summary>
  96. /// Load graphics content for the screen.
  97. /// </summary>
  98. public virtual void LoadContent() { }
  99. /// <summary>
  100. /// Unload content for the screen.
  101. /// </summary>
  102. public virtual void UnloadContent() { }
  103. #endregion
  104. #region Update and Draw
  105. /// <summary>
  106. /// Allows the screen to run logic, such as updating the transition position.
  107. /// Unlike HandleInput, this method is called regardless of whether the screen
  108. /// is active, hidden, or in the middle of a transition.
  109. /// </summary>
  110. ///
  111. public override void Update(GameTime gameTime)
  112. {
  113. // Read the keyboard and gamepad.
  114. //input.Update();
  115. // Make a copy of the master screen list, to avoid confusion if
  116. // the process of updating one screen adds or removes others.
  117. componentsToUpdate.Clear();
  118. foreach (Screen screen in Components)
  119. {
  120. componentsToUpdate.Add(screen);
  121. }
  122. bool otherScreenHasFocus = false;
  123. bool coveredByOtherScreen = false;
  124. // Loop as long as there are screens waiting to be updated.
  125. while (componentsToUpdate.Count > 0)
  126. {
  127. // Pop the topmost screen off the waiting list.
  128. Screen screen = componentsToUpdate[componentsToUpdate.Count - 1];
  129. componentsToUpdate.RemoveAt(componentsToUpdate.Count - 1);
  130. // Update the screen.
  131. screen.Update(gameTime);
  132. screen.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
  133. if (screen.ScreenState == ScreenState.TransitionOn ||
  134. screen.ScreenState == ScreenState.Active)
  135. {
  136. // If this is the first active screen we came across,
  137. // give it a chance to handle input.
  138. if (!otherScreenHasFocus)
  139. {
  140. //screen.HandleInput(input);
  141. otherScreenHasFocus = true;
  142. }
  143. // If this is an active non-popup, inform any subsequent
  144. // screens that they are covered by it.
  145. if (!screen.IsPopup)
  146. coveredByOtherScreen = true;
  147. }
  148. }
  149. base.Update(gameTime);
  150. }
  151. public virtual void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
  152. {
  153. HasFocus = otherScreenHasFocus;
  154. if (IsExiting)
  155. {
  156. // If the screen is going away to die, it should transition off.
  157. ScreenState = ScreenState.TransitionOff;
  158. if (!Transition.Update(gameTime, Transition.OffTime, 1))
  159. {
  160. // When the transition finishes, remove the screen.
  161. if (ComponentManager != null)
  162. ComponentManager.Remove(this);
  163. }
  164. }
  165. else if (coveredByOtherScreen && !IsPersistant)
  166. {
  167. // If the screen is covered by another, it should transition off.
  168. if (Transition.Update(gameTime, Transition.OffTime, 1))
  169. {
  170. // Still busy transitioning.
  171. ScreenState = ScreenState.TransitionOff;
  172. }
  173. else
  174. {
  175. // Transition finished!
  176. ScreenState = ScreenState.Hidden;
  177. }
  178. }
  179. else
  180. {
  181. // Otherwise the screen should transition on and become active.
  182. if (Transition.Update(gameTime, Transition.OnTime, -1))
  183. {
  184. // Still busy transitioning.
  185. ScreenState = ScreenState.TransitionOn;
  186. }
  187. else
  188. {
  189. // Transition finished!
  190. ScreenState = ScreenState.Active;
  191. }
  192. }
  193. ScriptingEngine.Update(gameTime);
  194. CollisionEngine.Update(gameTime);
  195. base.Update(gameTime);
  196. }
  197. /// <summary>
  198. /// Allows the screen to handle user input. Unlike Update, this method
  199. /// is only called when the screen is active, and not when some other
  200. /// screen has taken the focus.
  201. /// </summary>
  202. public virtual void HandleInput(PlayerInput input) { }
  203. /// <summary>
  204. /// This is called when the screen should draw itself.
  205. /// </summary>
  206. public override void Draw(GameTime gameTime)
  207. {
  208. base.Draw(gameTime);
  209. foreach (var screen in Components.Where(screen => screen.ScreenState != ScreenState.Hidden))
  210. {
  211. screen.Draw(gameTime);
  212. }
  213. if (CollisionEngine.Debug)
  214. {
  215. CollisionEngine.Draw(gameTime);
  216. }
  217. //base.Draw(gameTime);
  218. }
  219. #endregion
  220. #region Public Methods
  221. public void AddScreen(Screen component)
  222. {
  223. if (component.ComponentManager == null)
  224. {
  225. component.ComponentManager = this;
  226. component.IsExiting = false;
  227. component.Initialize();
  228. Components.Add(component);
  229. }
  230. else
  231. {
  232. //exception here?
  233. //throw new Exception("Component is already being managed by another component");
  234. }
  235. }
  236. public void Remove(Screen component)
  237. {
  238. Components.Remove(component);
  239. componentsToUpdate.Remove(component);
  240. component.ComponentManager = null;
  241. }
  242. /// <summary>
  243. /// Tells the screen to go away. Unlike ScreenManager.RemoveScreen, which
  244. /// instantly kills the screen, this method respects the transition timings
  245. /// and will give the screen a chance to gradually transition off.
  246. /// </summary>
  247. public void ExitScreen()
  248. {
  249. if (Transition.OffTime == TimeSpan.Zero)
  250. {
  251. // If the screen has a zero transition time, remove it immediately.
  252. ComponentManager.Remove(this);
  253. }
  254. else
  255. {
  256. // Otherwise flag that it should transition off and then exit.
  257. IsExiting = true;
  258. }
  259. }
  260. public static void FadeBackBufferToBlack(int alpha)
  261. {
  262. Viewport viewport = G.Game.GraphicsDevice.Viewport;
  263. Texture2D blankTexture = G.Content.Load<Texture2D>("blank");
  264. G.SpriteBatch.Draw(blankTexture,
  265. new Rectangle(0, 0, viewport.Width, viewport.Height),
  266. new Color(255, 255, 255, (byte)alpha));
  267. }
  268. #endregion
  269. #region DEBUG
  270. public void DrawDebugInfo(int x, int y)
  271. {
  272. int i = 12;
  273. foreach (Screen gc in Components)
  274. {
  275. i += i;
  276. G.SpriteBatch.DrawString(G.Content.Load<SpriteFont>(@"SpriteFonts\Arial"), gc.ID + " " + gc.ScreenState.ToString(), new Vector2(x, y + i), Color.Red);
  277. gc.DrawDebugInfo(x + 40, y + 10);
  278. }
  279. }
  280. #endregion
  281. }
  282. }