DemoGame.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. //-----------------------------------------------------------------------------
  2. // DemoGame.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using Microsoft.Xna.Framework;
  11. using Microsoft.Xna.Framework.Audio;
  12. using Microsoft.Xna.Framework.Content;
  13. using Microsoft.Xna.Framework.Graphics;
  14. using Microsoft.Xna.Framework.Input;
  15. using Microsoft.Xna.Framework.Input.Touch;
  16. using Microsoft.Xna.Framework.Media;
  17. namespace XnaGraphicsDemo
  18. {
  19. /// <summary>
  20. /// The main game class.
  21. /// </summary>
  22. public class DemoGame : Game
  23. {
  24. // Constants.
  25. const float TransitionSpeed = 1.5f;
  26. const float ZoomyTextLifespan = 0.75f;
  27. // Properties.
  28. public GraphicsDeviceManager Graphics { get; private set; }
  29. public SpriteBatch SpriteBatch { get; private set; }
  30. public SpriteFont Font { get; private set; }
  31. public SpriteFont BigFont { get; private set; }
  32. public Texture2D BlankTexture { get; private set; }
  33. public Matrix ScaleMatrix { get; private set; }
  34. // Fields.
  35. List<MenuComponent> menuComponents = new List<MenuComponent>();
  36. GameTime currentGameTime;
  37. // Transition effects provide swooshy crossfades when moving from one screen to another.
  38. float transitionTimer = float.MaxValue;
  39. int transitionMode;
  40. RenderTarget2D transitionRenderTarget;
  41. // Zoomy text provides visual feedback when selecting menu items.
  42. // This is implemented by the main game, rather than any individual menu
  43. // screen, because the zoomy effect from selecting a menu item needs to
  44. // display across the transition while that menu makes way for a new one.
  45. class ZoomyText
  46. {
  47. public string Text;
  48. public Vector2 Position;
  49. public float Age;
  50. }
  51. static List<ZoomyText> zoomyTexts = new List<ZoomyText>();
  52. const int BACK_BUFFER_WIDTH = 480;
  53. const int BACK_BUFFER_HEIGHT = 640;
  54. /// <summary>
  55. /// Constructor.
  56. /// </summary>
  57. public DemoGame()
  58. {
  59. Content.RootDirectory = "Content";
  60. Graphics = new GraphicsDeviceManager(this);
  61. Graphics.PreferredBackBufferWidth = BACK_BUFFER_WIDTH;
  62. Graphics.PreferredBackBufferHeight = BACK_BUFFER_HEIGHT;
  63. #if MOBILE
  64. Graphics.IsFullScreen = true;
  65. #endif
  66. IsMouseVisible = true;
  67. TargetElapsedTime = TimeSpan.FromSeconds(1 / 30.0);
  68. // Create all the different menu screens.
  69. menuComponents.Add(new TitleMenu(this));
  70. menuComponents.Add(new BasicDemo(this));
  71. menuComponents.Add(new DualDemo(this));
  72. menuComponents.Add(new AlphaDemo(this));
  73. menuComponents.Add(new SkinnedDemo(this));
  74. menuComponents.Add(new EnvmapDemo(this));
  75. menuComponents.Add(new ParticleDemo(this));
  76. // Set all the menu screens except the first to hidden and inactive.
  77. foreach (MenuComponent component in menuComponents)
  78. {
  79. component.Enabled = component.Visible = false;
  80. Components.Add(component);
  81. }
  82. // Make the title menu active and visible.
  83. menuComponents[0].Enabled = menuComponents[0].Visible = true;
  84. }
  85. /// <summary>
  86. /// Changes which menu screen is currently active.
  87. /// </summary>
  88. public void SetActiveMenu(int index)
  89. {
  90. // Trigger the transition effect.
  91. for (int i = 0; i < menuComponents.Count; i++)
  92. {
  93. if (menuComponents[i].Visible)
  94. {
  95. BeginTransition(i, index);
  96. break;
  97. }
  98. }
  99. // Mark the previous menu as inactive, and the new one as active.
  100. for (int i = 0; i < menuComponents.Count; i++)
  101. {
  102. menuComponents[i].Enabled = menuComponents[i].Visible = (i == index);
  103. menuComponents[i].Reset();
  104. }
  105. }
  106. /// <summary>
  107. /// Loads content and creates graphics resources.
  108. /// </summary>
  109. protected override void LoadContent()
  110. {
  111. SpriteBatch = new SpriteBatch(GraphicsDevice);
  112. Font = Content.Load<SpriteFont>("font");
  113. BigFont = Content.Load<SpriteFont>("BigFont");
  114. BlankTexture = new Texture2D(GraphicsDevice, 1, 1);
  115. BlankTexture.SetData(new Color[] { Color.White });
  116. transitionRenderTarget = new RenderTarget2D(GraphicsDevice, BACK_BUFFER_WIDTH, BACK_BUFFER_HEIGHT, false, SurfaceFormat.Color, DepthFormat.Depth24, 0, 0);
  117. }
  118. /// <summary>
  119. /// Updates the transition effect and zoomy text animations.
  120. /// </summary>
  121. protected override void Update(GameTime gameTime)
  122. {
  123. currentGameTime = gameTime;
  124. UpdateZoomyText(gameTime);
  125. if (transitionTimer < float.MaxValue)
  126. transitionTimer += (float)gameTime.ElapsedGameTime.TotalSeconds;
  127. // This updates game components, including the currently active menu screen.
  128. base.Update(gameTime);
  129. }
  130. /// <summary>
  131. /// Draws the game.
  132. /// </summary>
  133. protected override void Draw(GameTime gameTime)
  134. {
  135. ScaleMatrix = Matrix.CreateScale(Graphics.PreferredBackBufferWidth / BACK_BUFFER_WIDTH, Graphics.PreferredBackBufferHeight / BACK_BUFFER_HEIGHT, 1);
  136. // This draws game components, including the currently active menu screen.
  137. base.Draw(gameTime);
  138. DrawTransitionEffect();
  139. DrawZoomyText();
  140. }
  141. /// <summary>
  142. /// Begins a transition effect, capturing a copy of the current screen into the transitionRenderTarget.
  143. /// </summary>
  144. void BeginTransition(int oldMenuIndex, int newMenuIndex)
  145. {
  146. ScaleMatrix = Matrix.Identity;
  147. GraphicsDevice.SetRenderTarget(transitionRenderTarget);
  148. // Draw the old menu screen into the rendertarget.
  149. menuComponents[oldMenuIndex].Draw(currentGameTime);
  150. // Force the rendertarget alpha channel to fully opaque.
  151. SpriteBatch.Begin(0, BlendState.Additive);
  152. SpriteBatch.Draw(BlankTexture, new Rectangle(0, 0, BACK_BUFFER_WIDTH, BACK_BUFFER_HEIGHT), new Color(0, 0, 0, 255));
  153. SpriteBatch.End();
  154. GraphicsDevice.SetRenderTarget(null);
  155. // Initialize the transition state.
  156. transitionTimer = (float)TargetElapsedTime.TotalSeconds;
  157. transitionMode = newMenuIndex;
  158. }
  159. /// <summary>
  160. /// Draws the transition effect, displaying various animating pieces of the rendertarget
  161. /// which contains the previous scene image over the top of the new scene. There are
  162. /// various different effects which animate these pieces in different ways.
  163. /// </summary>
  164. void DrawTransitionEffect()
  165. {
  166. if (transitionTimer >= TransitionSpeed)
  167. return;
  168. SpriteBatch.Begin();
  169. float mu = transitionTimer / TransitionSpeed;
  170. float alpha = 1 - mu;
  171. switch (transitionMode)
  172. {
  173. case 1:
  174. // BasicEffect
  175. DrawOpenCurtainsTransition(alpha);
  176. break;
  177. case 2:
  178. case 5:
  179. // DualTexture
  180. // EnvironmentMap
  181. DrawSpinningSquaresTransition(mu, alpha);
  182. break;
  183. case 3:
  184. case 4:
  185. // AlphaTest and Skinning
  186. DrawChequeredAppearTransition(mu);
  187. break;
  188. case 6:
  189. // Particles
  190. DrawFallingLinesTransition(mu);
  191. break;
  192. default:
  193. // Returning to menu.
  194. DrawShrinkAndSpinTransition(mu, alpha);
  195. break;
  196. }
  197. SpriteBatch.End();
  198. }
  199. /// <summary>
  200. /// Transition effect where the screen splits in half, opening down the middle.
  201. /// </summary>
  202. void DrawOpenCurtainsTransition(float alpha)
  203. {
  204. int w = (int)(BACK_BUFFER_WIDTH / 2 * alpha * alpha);
  205. SpriteBatch.Draw(transitionRenderTarget, new Rectangle(0, 0, w, BACK_BUFFER_HEIGHT), new Rectangle(0, 0, BACK_BUFFER_WIDTH / 2, BACK_BUFFER_HEIGHT), Color.White * alpha);
  206. SpriteBatch.Draw(transitionRenderTarget, new Rectangle(BACK_BUFFER_WIDTH - w, 0, w, BACK_BUFFER_HEIGHT), new Rectangle(BACK_BUFFER_WIDTH / 2, 0, BACK_BUFFER_WIDTH / 2, BACK_BUFFER_HEIGHT), Color.White * alpha);
  207. }
  208. /// <summary>
  209. /// Transition effect where the screen splits into pieces, each spinning off in a different direction.
  210. /// </summary>
  211. void DrawSpinningSquaresTransition(float mu, float alpha)
  212. {
  213. Random random = new Random(23);
  214. for (int x = 0; x < 4; x++)
  215. {
  216. for (int y = 0; y < 8; y++)
  217. {
  218. Rectangle rect = new Rectangle(BACK_BUFFER_WIDTH * x / 4, BACK_BUFFER_HEIGHT * y / 8, BACK_BUFFER_WIDTH / 4, BACK_BUFFER_HEIGHT / 8);
  219. Vector2 origin = new Vector2(rect.Width, rect.Height) / 2;
  220. float rotation = (float)(random.NextDouble() - 0.5) * mu * mu * 2;
  221. float scale = 1 + (float)(random.NextDouble() - 0.5f) * mu * mu;
  222. Vector2 pos = new Vector2(rect.Center.X, rect.Center.Y);
  223. pos.X += (float)(random.NextDouble() - 0.5) * mu * mu * BACK_BUFFER_HEIGHT / 2;
  224. pos.Y += (float)(random.NextDouble() - 0.5) * mu * mu * BACK_BUFFER_HEIGHT / 2;
  225. SpriteBatch.Draw(transitionRenderTarget, pos, rect, Color.White * alpha, rotation, origin, scale, 0, 0);
  226. }
  227. }
  228. }
  229. /// <summary>
  230. /// Transition effect where each square of the image appears at a different time.
  231. /// </summary>
  232. void DrawChequeredAppearTransition(float mu)
  233. {
  234. Random random = new Random(23);
  235. for (int x = 0; x < 8; x++)
  236. {
  237. for (int y = 0; y < 16; y++)
  238. {
  239. Rectangle rect = new Rectangle(BACK_BUFFER_WIDTH * x / 8, BACK_BUFFER_HEIGHT * y / 16, BACK_BUFFER_WIDTH / 8, BACK_BUFFER_HEIGHT / 16);
  240. if (random.NextDouble() > mu * mu)
  241. SpriteBatch.Draw(transitionRenderTarget, rect, rect, Color.White);
  242. }
  243. }
  244. // The zoomy text effect doesn't look so good with this
  245. // particular transition effect, so we temporarily disable it.
  246. zoomyTexts.Clear();
  247. }
  248. /// <summary>
  249. /// Transition effect where the image dissolves into a sequence of vertically falling lines.
  250. /// </summary>
  251. void DrawFallingLinesTransition(float mu)
  252. {
  253. Random random = new Random(23);
  254. const int segments = 60;
  255. for (int x = 0; x < segments; x++)
  256. {
  257. Rectangle rect = new Rectangle(BACK_BUFFER_WIDTH * x / segments, 0, BACK_BUFFER_WIDTH / segments, BACK_BUFFER_HEIGHT);
  258. Vector2 pos = new Vector2(rect.X, 0);
  259. pos.Y += BACK_BUFFER_HEIGHT * (float)Math.Pow(mu, random.NextDouble() * 10);
  260. SpriteBatch.Draw(transitionRenderTarget, pos, rect, Color.White);
  261. }
  262. }
  263. /// <summary>
  264. /// Transition effect where the image spins off toward the bottom left of the screen.
  265. /// </summary>
  266. void DrawShrinkAndSpinTransition(float mu, float alpha)
  267. {
  268. Vector2 origin = new Vector2(BACK_BUFFER_WIDTH / 2, BACK_BUFFER_HEIGHT / 2);
  269. Vector2 translate = (new Vector2(32, BACK_BUFFER_HEIGHT - 32) - origin) * mu * mu;
  270. float rotation = mu * mu * -4;
  271. float scale = alpha * alpha;
  272. Color tint = Color.White * (float)Math.Sqrt(alpha);
  273. SpriteBatch.Draw(transitionRenderTarget, origin + translate, null, tint, rotation, origin, scale, 0, 0);
  274. }
  275. /// <summary>
  276. /// Creates a new zoomy text menu item selection effect.
  277. /// </summary>
  278. public static void SpawnZoomyText(string text, Vector2 position)
  279. {
  280. zoomyTexts.Add(new ZoomyText { Text = text, Position = position });
  281. }
  282. /// <summary>
  283. /// Updates the zoomy text animations.
  284. /// </summary>
  285. static void UpdateZoomyText(GameTime gameTime)
  286. {
  287. int i = 0;
  288. while (i < zoomyTexts.Count)
  289. {
  290. zoomyTexts[i].Age += (float)gameTime.ElapsedGameTime.TotalSeconds;
  291. if (zoomyTexts[i].Age >= ZoomyTextLifespan)
  292. zoomyTexts.RemoveAt(i);
  293. else
  294. i++;
  295. }
  296. }
  297. /// <summary>
  298. /// Draws the zoomy text animations.
  299. /// </summary>
  300. void DrawZoomyText()
  301. {
  302. if (zoomyTexts.Count <= 0)
  303. return;
  304. SpriteBatch.Begin(0, null, null, null, null, null, ScaleMatrix);
  305. foreach (ZoomyText zoomyText in zoomyTexts)
  306. {
  307. Vector2 pos = zoomyText.Position + Font.MeasureString(zoomyText.Text) / 2;
  308. float age = zoomyText.Age / ZoomyTextLifespan;
  309. float sqrtAge = (float)Math.Sqrt(age);
  310. float scale = 0.333f + sqrtAge * 2f;
  311. float alpha = 1 - age;
  312. SpriteFont font = BigFont;
  313. // Our BigFont only contains characters a-z, so if the text
  314. // contains any numbers, we have to use the other font instead.
  315. foreach (char ch in zoomyText.Text)
  316. {
  317. if (char.IsDigit(ch))
  318. {
  319. font = Font;
  320. scale *= 2;
  321. break;
  322. }
  323. }
  324. Vector2 origin = font.MeasureString(zoomyText.Text) / 2;
  325. SpriteBatch.DrawString(font, zoomyText.Text, pos, Color.Lerp(new Color(64, 64, 255), Color.White, sqrtAge) * alpha, 0, origin, scale, 0, 0);
  326. }
  327. SpriteBatch.End();
  328. }
  329. }
  330. }