MenuScreen.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. //-----------------------------------------------------------------------------
  2. // MenuScreen.cs
  3. //
  4. // XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. using Microsoft.Xna.Framework;
  10. using Microsoft.Xna.Framework.Graphics;
  11. using Microsoft.Xna.Framework.Input.Touch;
  12. using Microsoft.Xna.Framework.Input;
  13. namespace GameStateManagement
  14. {
  15. /// <summary>
  16. /// Base class for screens that contain a menu of options. The user can
  17. /// move up and down to select an entry, or cancel to back out of the screen.
  18. /// </summary>
  19. abstract class MenuScreen : GameScreen
  20. {
  21. List<MenuEntry> menuEntries = new List<MenuEntry>();
  22. int selectedEntry = 0;
  23. string menuTitle;
  24. /// <summary>
  25. /// Gets the list of menu entries, so derived classes can add
  26. /// or change the menu contents.
  27. /// </summary>
  28. protected IList<MenuEntry> MenuEntries
  29. {
  30. get { return menuEntries; }
  31. }
  32. /// <summary>
  33. /// Constructor.
  34. /// </summary>
  35. public MenuScreen(string menuTitle)
  36. {
  37. this.menuTitle = menuTitle;
  38. TransitionOnTime = TimeSpan.FromSeconds(0.5);
  39. TransitionOffTime = TimeSpan.FromSeconds(0.5);
  40. }
  41. /// <summary>
  42. /// Responds to user input, changing the selected entry and accepting
  43. /// or cancelling the menu.
  44. /// </summary>
  45. public override void HandleInput(InputState input)
  46. {
  47. // Move to the previous menu entry?
  48. if (input.IsMenuUp(ControllingPlayer))
  49. {
  50. selectedEntry--;
  51. if (selectedEntry < 0)
  52. selectedEntry = menuEntries.Count - 1;
  53. }
  54. // Move to the next menu entry?
  55. if (input.IsMenuDown(ControllingPlayer))
  56. {
  57. selectedEntry++;
  58. if (selectedEntry >= menuEntries.Count)
  59. selectedEntry = 0;
  60. }
  61. // Accept or cancel the menu? We pass in our ControllingPlayer, which may
  62. // either be null (to accept input from any player) or a specific index.
  63. // If we pass a null controlling player, the InputState helper returns to
  64. // us which player actually provided the input. We pass that through to
  65. // OnSelectEntry and OnCancel, so they can tell which player triggered them.
  66. PlayerIndex playerIndex;
  67. if (input.IsMenuSelect(ControllingPlayer, out playerIndex))
  68. {
  69. OnSelectEntry(selectedEntry, playerIndex);
  70. }
  71. else if (input.IsMenuCancel(ControllingPlayer, out playerIndex))
  72. {
  73. OnCancel(playerIndex);
  74. }
  75. }
  76. /// <summary>
  77. /// Handler for when the user has chosen a menu entry.
  78. /// </summary>
  79. protected virtual void OnSelectEntry(int entryIndex, PlayerIndex playerIndex)
  80. {
  81. menuEntries[entryIndex].OnSelectEntry(playerIndex);
  82. }
  83. /// <summary>
  84. /// Handler for when the user has cancelled the menu.
  85. /// </summary>
  86. protected virtual void OnCancel(PlayerIndex playerIndex)
  87. {
  88. ExitScreen();
  89. }
  90. /// <summary>
  91. /// Helper overload makes it easy to use OnCancel as a MenuEntry event handler.
  92. /// </summary>
  93. protected void OnCancel(object sender, PlayerIndexEventArgs e)
  94. {
  95. OnCancel(e.PlayerIndex);
  96. }
  97. /// <summary>
  98. /// Allows the screen the chance to position the menu entries. By default
  99. /// all menu entries are lined up in a vertical list, centered on the screen.
  100. /// </summary>
  101. protected virtual void UpdateMenuEntryLocations()
  102. {
  103. // Make the menu slide into place during transitions, using a
  104. // power curve to make things look more interesting (this makes
  105. // the movement slow down as it nears the end).
  106. float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
  107. // start at Y = 175; each X value is generated per entry
  108. Vector2 position = new Vector2(0f, 175f);
  109. // update each menu entry's location in turn
  110. for (int i = 0; i < menuEntries.Count; i++)
  111. {
  112. MenuEntry menuEntry = menuEntries[i];
  113. // each entry is to be centered horizontally
  114. position.X = ScreenManager.GraphicsDevice.Viewport.Width / 2 - menuEntry.GetWidth(this) / 2;
  115. if (ScreenState == ScreenState.TransitionOn)
  116. position.X -= transitionOffset * 256;
  117. else
  118. position.X += transitionOffset * 512;
  119. // set the entry's position
  120. menuEntry.Position = position;
  121. // move down for the next entry the size of this entry
  122. position.Y += menuEntry.GetHeight(this);
  123. }
  124. }
  125. /// <summary>
  126. /// Updates the menu.
  127. /// </summary>
  128. public override void Update(GameTime gameTime, bool otherScreenHasFocus,
  129. bool coveredByOtherScreen)
  130. {
  131. base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
  132. // Update each nested MenuEntry object.
  133. for (int i = 0; i < menuEntries.Count; i++)
  134. {
  135. bool isSelected = IsActive && (i == selectedEntry);
  136. menuEntries[i].Update(this, isSelected, gameTime);
  137. }
  138. }
  139. /// <summary>
  140. /// Draws the menu.
  141. /// </summary>
  142. public override void Draw(GameTime gameTime)
  143. {
  144. // make sure our entries are in the right place before we draw them
  145. UpdateMenuEntryLocations();
  146. GraphicsDevice graphics = ScreenManager.GraphicsDevice;
  147. SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
  148. SpriteFont font = ScreenManager.Font;
  149. spriteBatch.Begin();
  150. // Draw each menu entry in turn.
  151. for (int i = 0; i < menuEntries.Count; i++)
  152. {
  153. MenuEntry menuEntry = menuEntries[i];
  154. bool isSelected = IsActive && (i == selectedEntry);
  155. menuEntry.Draw(this, isSelected, gameTime);
  156. }
  157. // Make the menu slide into place during transitions, using a
  158. // power curve to make things look more interesting (this makes
  159. // the movement slow down as it nears the end).
  160. float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
  161. // Draw the menu title centered on the screen
  162. Vector2 titlePosition = new Vector2(graphics.Viewport.Width / 2, 80);
  163. Vector2 titleOrigin = font.MeasureString(menuTitle) / 2;
  164. Color titleColor = new Color(192, 192, 192) * TransitionAlpha;
  165. float titleScale = 1.25f;
  166. titlePosition.Y -= transitionOffset * 100;
  167. spriteBatch.DrawString(font, menuTitle, titlePosition, titleColor, 0,
  168. titleOrigin, titleScale, SpriteEffects.None, 0);
  169. spriteBatch.End();
  170. }
  171. }
  172. }