ParticleSampleGame.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // ParticleSampleGame.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 System.Collections.Generic;
  12. using System.Text;
  13. using Microsoft.Xna.Framework;
  14. using Microsoft.Xna.Framework.Graphics;
  15. using Microsoft.Xna.Framework.Content;
  16. using Microsoft.Xna.Framework.Input;
  17. using Microsoft.Xna.Framework.Input.Touch;
  18. #endregion
  19. namespace ParticleSample
  20. {
  21. /// <summary>
  22. /// This is the main type for the ParticleSample, and inherits from the Framework's
  23. /// Game class. It creates three different kinds of ParticleSystems, and then adds
  24. /// them to its components collection. It also has keeps a random number generator,
  25. /// a SpriteBatch, and a ContentManager that the different classes in this sample
  26. /// can share.
  27. /// </summary>
  28. public class ParticleSampleGame : Microsoft.Xna.Framework.Game
  29. {
  30. #region Fields and Properties
  31. GraphicsDeviceManager graphics;
  32. // The particle systems will all need a SpriteBatch to draw their particles,
  33. // so let's make one they can share. We'll use this to draw our SpriteFont
  34. // too.
  35. SpriteBatch spriteBatch;
  36. public SpriteBatch SpriteBatch
  37. {
  38. get { return spriteBatch; }
  39. }
  40. // Used to draw the instructions on the screen.
  41. SpriteFont font;
  42. // a random number generator that the whole sample can share.
  43. private static Random random = new Random();
  44. public static Random Random
  45. {
  46. get { return random; }
  47. }
  48. // Here's the really fun part of the sample, the particle systems! These are
  49. // drawable game components, so we can just add them to the components
  50. // collection. Read more about each particle system in their respective source
  51. // files.
  52. ExplosionParticleSystem explosion;
  53. ExplosionSmokeParticleSystem smoke;
  54. SmokePlumeParticleSystem smokePlume;
  55. // State is an enum that represents which effect we're currently demoing.
  56. enum State
  57. {
  58. Explosions,
  59. SmokePlume
  60. };
  61. // the number of values in the "State" enum.
  62. const int NumStates = 2;
  63. State currentState = State.Explosions;
  64. // a timer that will tell us when it's time to trigger another explosion.
  65. const float TimeBetweenExplosions = 2.0f;
  66. float timeTillExplosion = 0.0f;
  67. // keep a timer that will tell us when it's time to add more particles to the
  68. // smoke plume.
  69. const float TimeBetweenSmokePlumePuffs = .5f;
  70. float timeTillPuff = 0.0f;
  71. // keep track of the last frame's keyboard and gamepad state, so that we know
  72. // if the user has pressed a button.
  73. KeyboardState lastKeyboardState;
  74. GamePadState lastGamepadState;
  75. #endregion
  76. #region Initialization
  77. public ParticleSampleGame()
  78. {
  79. graphics = new GraphicsDeviceManager(this);
  80. #if WINDOWS_PHONE
  81. graphics.IsFullScreen = true;
  82. // Frame rate is 30 fps by default for Windows Phone.
  83. TargetElapsedTime = TimeSpan.FromTicks(333333);
  84. #endif
  85. Content.RootDirectory = "Content";
  86. // create the particle systems and add them to the components list.
  87. // we should never see more than one explosion at once
  88. explosion = new ExplosionParticleSystem(this, 1);
  89. Components.Add(explosion);
  90. // but the smoke from the explosion lingers a while.
  91. smoke = new ExplosionSmokeParticleSystem(this, 2);
  92. Components.Add(smoke);
  93. // we'll see lots of these effects at once; this is ok
  94. // because they have a fairly small number of particles per effect.
  95. smokePlume = new SmokePlumeParticleSystem(this, 9);
  96. Components.Add(smokePlume);
  97. // enable the tap gesture for changing particle effects
  98. TouchPanel.EnabledGestures = GestureType.Tap;
  99. }
  100. /// <summary>
  101. /// Load your graphics content.
  102. /// </summary>
  103. protected override void LoadContent()
  104. {
  105. spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
  106. font = Content.Load<SpriteFont>("font");
  107. }
  108. #endregion
  109. #region Update and Draw
  110. /// <summary>
  111. /// Allows the game to run logic such as updating the world,
  112. /// checking for collisions, gathering input and playing audio.
  113. /// </summary>
  114. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  115. protected override void Update(GameTime gameTime)
  116. {
  117. // check the input devices to see if someone has decided they want to see
  118. // the other effect, if they want to quit.
  119. HandleInput();
  120. float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
  121. switch (currentState)
  122. {
  123. // if we should be demoing the explosions effect, check to see if it's
  124. // time for a new explosion.
  125. case State.Explosions:
  126. UpdateExplosions(dt);
  127. break;
  128. // if we're showing off the smoke plume, check to see if it's time for a
  129. // new puff of smoke.
  130. case State.SmokePlume:
  131. UpdateSmokePlume(dt);
  132. break;
  133. }
  134. // the base update will handle updating the particle systems themselves,
  135. // because we added them to the components collection.
  136. base.Update(gameTime);
  137. }
  138. // this function is called when we want to demo the smoke plume effect. it
  139. // updates the timeTillPuff timer, and adds more particles to the plume when
  140. // necessary.
  141. private void UpdateSmokePlume(float dt)
  142. {
  143. timeTillPuff -= dt;
  144. if (timeTillPuff < 0)
  145. {
  146. Vector2 where = Vector2.Zero;
  147. // add more particles at the bottom of the screen, halfway across.
  148. where.X = graphics.GraphicsDevice.Viewport.Width / 2;
  149. where.Y = graphics.GraphicsDevice.Viewport.Height;
  150. smokePlume.AddParticles(where);
  151. // and then reset the timer.
  152. timeTillPuff = TimeBetweenSmokePlumePuffs;
  153. }
  154. }
  155. // this function is called when we want to demo the explosion effect. it
  156. // updates the timeTillExplosion timer, and starts another explosion effect
  157. // when the timer reaches zero.
  158. private void UpdateExplosions(float dt)
  159. {
  160. timeTillExplosion -= dt;
  161. if (timeTillExplosion < 0)
  162. {
  163. Vector2 where = Vector2.Zero;
  164. // create the explosion at some random point on the screen.
  165. where.X = RandomBetween(0, graphics.GraphicsDevice.Viewport.Width);
  166. where.Y = RandomBetween(0, graphics.GraphicsDevice.Viewport.Height);
  167. // the overall explosion effect is actually comprised of two particle
  168. // systems: the fiery bit, and the smoke behind it. add particles to
  169. // both of those systems.
  170. explosion.AddParticles(where);
  171. smoke.AddParticles(where);
  172. // reset the timer.
  173. timeTillExplosion = TimeBetweenExplosions;
  174. }
  175. }
  176. /// <summary>
  177. /// This is called when the game should draw itself.
  178. /// </summary>
  179. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  180. protected override void Draw(GameTime gameTime)
  181. {
  182. graphics.GraphicsDevice.Clear(Color.Black);
  183. spriteBatch.Begin();
  184. // draw some instructions on the screen
  185. string message = string.Format("Current effect: {0}!\n" +
  186. "Hit the A button or space bar, or tap the screen, to switch.\n" +
  187. "Hit the F key to toggle full screen.\n\n" +
  188. "Free particles:\n" +
  189. " ExplosionParticleSystem: {1}\n" +
  190. " ExplosionSmokeParticleSystem: {2}\n" +
  191. " SmokePlumeParticleSystem: {3}",
  192. currentState, explosion.FreeParticleCount,
  193. smoke.FreeParticleCount, smokePlume.FreeParticleCount );
  194. spriteBatch.DrawString(font, message, new Vector2(50, 50), Color.White);
  195. spriteBatch.End();
  196. base.Draw(gameTime);
  197. }
  198. // This function will check to see if the user has just pushed the A button or
  199. // the space bar. If so, we should go to the next effect.
  200. private void HandleInput()
  201. {
  202. KeyboardState currentKeyboardState = Keyboard.GetState();
  203. GamePadState currentGamePadState = GamePad.GetState(PlayerIndex.One);
  204. // Allows the game to exit
  205. if (currentGamePadState.Buttons.Back == ButtonState.Pressed ||
  206. currentKeyboardState.IsKeyDown(Keys.Escape))
  207. this.Exit();
  208. // check to see if someone has just released the space bar.
  209. bool keyboardSpace =
  210. currentKeyboardState.IsKeyUp(Keys.Space) &&
  211. lastKeyboardState.IsKeyDown(Keys.Space);
  212. // check to see if someone has just released the 'F' key.
  213. bool keyboardF =
  214. currentKeyboardState.IsKeyUp(Keys.F) &&
  215. lastKeyboardState.IsKeyDown(Keys.F);
  216. // check the gamepad to see if someone has just released the A button.
  217. bool gamepadA =
  218. currentGamePadState.Buttons.A == ButtonState.Pressed &&
  219. lastGamepadState.Buttons.A == ButtonState.Released;
  220. // check our gestures to see if someone has tapped the screen. we want
  221. // to read all available gestures even if a tap occurred so we clear
  222. // the queue.
  223. bool tapGesture = false;
  224. while (TouchPanel.IsGestureAvailable)
  225. {
  226. GestureSample sample = TouchPanel.ReadGesture();
  227. if (sample.GestureType == GestureType.Tap)
  228. {
  229. tapGesture = true;
  230. }
  231. }
  232. // if either the A button or the space bar was just released, or the screen
  233. // was tapped, move to the next state. Doing modulus by the number of
  234. // states lets us wrap back around to the first state.
  235. if (keyboardSpace || gamepadA || tapGesture)
  236. {
  237. currentState = (State)((int)(currentState + 1) % NumStates);
  238. }
  239. if (keyboardF)
  240. {
  241. graphics.ToggleFullScreen();
  242. //Window.Window.IsVisible = true;
  243. //Window.Window.MakeKeyAndOrderFront(Window);
  244. }
  245. lastKeyboardState = currentKeyboardState;
  246. lastGamepadState = currentGamePadState;
  247. }
  248. #endregion
  249. #region Helper Functions
  250. // a handy little function that gives a random float between two
  251. // values. This will be used in several places in the sample, in particilar in
  252. // ParticleSystem.InitializeParticle.
  253. public static float RandomBetween(float min, float max)
  254. {
  255. return min + (float)random.NextDouble() * (max - min);
  256. }
  257. #endregion
  258. }
  259. }