Game.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. //-----------------------------------------------------------------------------
  2. // Game.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 Microsoft.Xna.Framework;
  10. using Microsoft.Xna.Framework.Content;
  11. using Microsoft.Xna.Framework.Graphics;
  12. using Microsoft.Xna.Framework.Input;
  13. namespace Particle3DSample
  14. {
  15. /// <summary>
  16. /// Sample showing how to implement a particle system entirely
  17. /// on the GPU, using the vertex shader to animate particles.
  18. /// </summary>
  19. public class Particle3DSampleGame : Game
  20. {
  21. GraphicsDeviceManager graphics;
  22. SpriteBatch spriteBatch;
  23. SpriteFont font;
  24. //Model grid;
  25. // This sample uses five different particle systems.
  26. ParticleSystem explosionParticles;
  27. ParticleSystem explosionSmokeParticles;
  28. ParticleSystem projectileTrailParticles;
  29. ParticleSystem smokePlumeParticles;
  30. ParticleSystem fireParticles;
  31. // The sample can switch between three different visual effects.
  32. enum ParticleState
  33. {
  34. Explosions,
  35. SmokePlume,
  36. RingOfFire,
  37. };
  38. ParticleState currentState = ParticleState.Explosions;
  39. // The explosions effect works by firing projectiles up into the
  40. // air, so we need to keep track of all the active projectiles.
  41. List<Projectile> projectiles = new List<Projectile> ();
  42. TimeSpan timeToNextProjectile = TimeSpan.Zero;
  43. // Random number generator for the fire effect.
  44. Random random = new Random ();
  45. // Input state.
  46. KeyboardState currentKeyboardState;
  47. GamePadState currentGamePadState;
  48. KeyboardState lastKeyboardState;
  49. GamePadState lastGamePadState;
  50. // Camera state.
  51. float cameraArc = -5;
  52. float cameraRotation = 0;
  53. float cameraDistance = 200;
  54. /// <summary>
  55. /// Constructor.
  56. /// </summary>
  57. public Particle3DSampleGame ()
  58. {
  59. graphics = new GraphicsDeviceManager (this);
  60. Content.RootDirectory = "Content";
  61. // Construct our particle system components.
  62. explosionParticles = new ParticleSystem (this, Content, "ExplosionSettings");
  63. explosionSmokeParticles = new ParticleSystem (this, Content, "ExplosionSmokeSettings");
  64. projectileTrailParticles = new ParticleSystem (this, Content, "ProjectileTrailSettings");
  65. smokePlumeParticles = new ParticleSystem (this, Content, "SmokePlumeSettings");
  66. fireParticles = new ParticleSystem (this, Content, "FireSettings");
  67. // Set the draw order so the explosions and fire
  68. // will appear over the top of the smoke.
  69. smokePlumeParticles.DrawOrder = 100;
  70. explosionSmokeParticles.DrawOrder = 200;
  71. projectileTrailParticles.DrawOrder = 300;
  72. explosionParticles.DrawOrder = 400;
  73. fireParticles.DrawOrder = 500;
  74. // Register the particle system components.
  75. Components.Add (explosionParticles);
  76. Components.Add (explosionSmokeParticles);
  77. Components.Add (projectileTrailParticles);
  78. Components.Add (smokePlumeParticles);
  79. Components.Add (fireParticles);
  80. }
  81. /// <summary>
  82. /// Load your graphics content.
  83. /// </summary>
  84. protected override void LoadContent ()
  85. {
  86. spriteBatch = new SpriteBatch (graphics.GraphicsDevice);
  87. //font = Content.Load<SpriteFont> ("Arial");
  88. font = Content.Load<SpriteFont> ("font");
  89. //grid = Content.Load<Model> ("grid");
  90. }
  91. /// <summary>
  92. /// Allows the game to run logic.
  93. /// </summary>
  94. protected override void Update (GameTime gameTime)
  95. {
  96. HandleInput ();
  97. UpdateCamera (gameTime);
  98. switch (currentState) {
  99. case ParticleState.Explosions:
  100. UpdateExplosions (gameTime);
  101. break;
  102. case ParticleState.SmokePlume:
  103. UpdateSmokePlume ();
  104. break;
  105. case ParticleState.RingOfFire:
  106. UpdateFire ();
  107. break;
  108. }
  109. UpdateProjectiles (gameTime);
  110. base.Update (gameTime);
  111. }
  112. /// <summary>
  113. /// Helper for updating the explosions effect.
  114. /// </summary>
  115. void UpdateExplosions (GameTime gameTime)
  116. {
  117. timeToNextProjectile -= gameTime.ElapsedGameTime;
  118. if (timeToNextProjectile <= TimeSpan.Zero) {
  119. // Create a new projectile once per second. The real work of moving
  120. // and creating particles is handled inside the Projectile class.
  121. projectiles.Add (new Projectile (explosionParticles,
  122. explosionSmokeParticles,
  123. projectileTrailParticles));
  124. timeToNextProjectile += TimeSpan.FromSeconds (1);
  125. }
  126. }
  127. /// <summary>
  128. /// Helper for updating the list of active projectiles.
  129. /// </summary>
  130. void UpdateProjectiles (GameTime gameTime)
  131. {
  132. int i = 0;
  133. while (i < projectiles.Count) {
  134. if (!projectiles [i].Update (gameTime)) {
  135. // Remove projectiles at the end of their life.
  136. projectiles.RemoveAt (i);
  137. } else {
  138. // Advance to the next projectile.
  139. i++;
  140. }
  141. }
  142. }
  143. /// <summary>
  144. /// Helper for updating the smoke plume effect.
  145. /// </summary>
  146. void UpdateSmokePlume ()
  147. {
  148. // This is trivial: we just create one new smoke particle per frame.
  149. smokePlumeParticles.AddParticle (Vector3.Zero, Vector3.Zero);
  150. }
  151. /// <summary>
  152. /// Helper for updating the fire effect.
  153. /// </summary>
  154. void UpdateFire ()
  155. {
  156. const
  157. int fireParticlesPerFrame = 20 ;
  158. // Create a number of fire particles, randomly positioned around a circle.
  159. for (int i = 0; i < fireParticlesPerFrame; i++) {
  160. fireParticles.AddParticle (RandomPointOnCircle (), Vector3.Zero);
  161. }
  162. // Create one smoke particle per frmae, too.
  163. smokePlumeParticles.AddParticle (RandomPointOnCircle (), Vector3.Zero);
  164. }
  165. /// <summary>
  166. /// Helper used by the UpdateFire method. Chooses a random location
  167. /// around a circle, at which a fire particle will be created.
  168. /// </summary>
  169. Vector3 RandomPointOnCircle ()
  170. {
  171. const
  172. float radius = 30 ;
  173. const
  174. float height = 40 ;
  175. double angle = random.NextDouble () * Math.PI * 2;
  176. float x = (float)Math.Cos (angle);
  177. float y = (float)Math.Sin (angle);
  178. return new Vector3 (x * radius, y * radius + height, 0);
  179. }
  180. /// <summary>
  181. /// This is called when the game should draw itself.
  182. /// </summary>
  183. protected override void Draw (GameTime gameTime)
  184. {
  185. GraphicsDevice device = graphics.GraphicsDevice;
  186. device.Clear (Color.CornflowerBlue);
  187. // Compute camera matrices.
  188. float aspectRatio = (float)device.Viewport.Width /
  189. (float)device.Viewport.Height;
  190. Matrix view = Matrix.CreateTranslation (0, -25, 0) *
  191. Matrix.CreateRotationY (MathHelper.ToRadians (cameraRotation)) *
  192. Matrix.CreateRotationX (MathHelper.ToRadians (cameraArc)) *
  193. Matrix.CreateLookAt (new Vector3 (0, 0, -cameraDistance),
  194. new Vector3 (0, 0, 0), Vector3.Up);
  195. Matrix projection = Matrix.CreatePerspectiveFieldOfView (MathHelper.PiOver4,
  196. aspectRatio,
  197. 1, 10000);
  198. // Pass camera matrices through to the particle system components.
  199. explosionParticles.SetCamera (view, projection);
  200. explosionSmokeParticles.SetCamera (view, projection);
  201. projectileTrailParticles.SetCamera (view, projection);
  202. smokePlumeParticles.SetCamera (view, projection);
  203. fireParticles.SetCamera (view, projection);
  204. // Draw our background grid and message text.
  205. DrawGrid (view, projection);
  206. DrawMessage ();
  207. // This will draw the particle system components.
  208. base.Draw (gameTime);
  209. }
  210. /// <summary>
  211. /// Helper for drawing the background grid model.
  212. /// </summary>
  213. void DrawGrid (Matrix view, Matrix projection)
  214. {
  215. GraphicsDevice device = graphics.GraphicsDevice;
  216. device.BlendState = BlendState.Opaque;
  217. device.DepthStencilState = DepthStencilState.Default;
  218. device.SamplerStates [0] = SamplerState.LinearWrap;
  219. //grid.Draw (Matrix.Identity, view, projection);
  220. }
  221. /// <summary>
  222. /// Helper for drawing our message text.
  223. /// </summary>
  224. void DrawMessage ()
  225. {
  226. string message = string.Format ("Current effect: {0}!!!\n" +
  227. "Hit the A button or space bar to switch.",
  228. currentState);
  229. spriteBatch.Begin ();
  230. spriteBatch.DrawString (font, message, new Vector2 (50, 50), Color.White);
  231. spriteBatch.End ();
  232. }
  233. /// <summary>
  234. /// Handles input for quitting the game and cycling
  235. /// through the different particle effects.
  236. /// </summary>
  237. void HandleInput ()
  238. {
  239. lastKeyboardState = currentKeyboardState;
  240. lastGamePadState = currentGamePadState;
  241. currentKeyboardState = Keyboard.GetState ();
  242. currentGamePadState = GamePad.GetState (PlayerIndex.One);
  243. // Check for exit.
  244. if (currentKeyboardState.IsKeyDown (Keys.Escape) ||
  245. currentGamePadState.Buttons.Back == ButtonState.Pressed) {
  246. Exit ();
  247. }
  248. // Check for changing the active particle effect.
  249. if (((currentKeyboardState.IsKeyDown (Keys.Space) &&
  250. (lastKeyboardState.IsKeyUp (Keys.Space))) ||
  251. ((currentGamePadState.Buttons.A == ButtonState.Pressed)) &&
  252. (lastGamePadState.Buttons.A == ButtonState.Released))) {
  253. currentState++;
  254. if (currentState > ParticleState.RingOfFire)
  255. currentState = 0;
  256. }
  257. }
  258. /// <summary>
  259. /// Handles input for moving the camera.
  260. /// </summary>
  261. void UpdateCamera (GameTime gameTime)
  262. {
  263. float time = (float)gameTime.ElapsedGameTime.TotalMilliseconds;
  264. // Check for input to rotate the camera up and down around the model.
  265. if (currentKeyboardState.IsKeyDown (Keys.Up) ||
  266. currentKeyboardState.IsKeyDown (Keys.W)) {
  267. cameraArc += time * 0.025f;
  268. }
  269. if (currentKeyboardState.IsKeyDown (Keys.Down) ||
  270. currentKeyboardState.IsKeyDown (Keys.S)) {
  271. cameraArc -= time * 0.025f;
  272. }
  273. cameraArc += currentGamePadState.ThumbSticks.Right.Y * time * 0.05f;
  274. // Limit the arc movement.
  275. if (cameraArc > 90.0f)
  276. cameraArc = 90.0f;
  277. else if (cameraArc < -90.0f)
  278. cameraArc = -90.0f;
  279. // Check for input to rotate the camera around the model.
  280. if (currentKeyboardState.IsKeyDown (Keys.Right) ||
  281. currentKeyboardState.IsKeyDown (Keys.D)) {
  282. cameraRotation += time * 0.05f;
  283. }
  284. if (currentKeyboardState.IsKeyDown (Keys.Left) ||
  285. currentKeyboardState.IsKeyDown (Keys.A)) {
  286. cameraRotation -= time * 0.05f;
  287. }
  288. cameraRotation += currentGamePadState.ThumbSticks.Right.X * time * 0.1f;
  289. // Check for input to zoom camera in and out.
  290. if (currentKeyboardState.IsKeyDown (Keys.Z))
  291. cameraDistance += time * 0.25f;
  292. if (currentKeyboardState.IsKeyDown (Keys.X))
  293. cameraDistance -= time * 0.25f;
  294. cameraDistance += currentGamePadState.Triggers.Left * time * 0.5f;
  295. cameraDistance -= currentGamePadState.Triggers.Right * time * 0.5f;
  296. // Limit the camera distance.
  297. if (cameraDistance > 500)
  298. cameraDistance = 500;
  299. else if (cameraDistance < 10)
  300. cameraDistance = 10;
  301. if (currentGamePadState.Buttons.RightStick == ButtonState.Pressed ||
  302. currentKeyboardState.IsKeyDown (Keys.R)) {
  303. cameraArc = -5;
  304. cameraRotation = 0;
  305. cameraDistance = 200;
  306. }
  307. }
  308. }
  309. // /// <summary>
  310. // /// The main entry point for the application.
  311. // /// </summary>
  312. // static class Program
  313. // {
  314. // static void Main()
  315. // {
  316. // using (Particle3DSampleGame game = new Particle3DSampleGame())
  317. // {
  318. // game.Run();
  319. // }
  320. // }
  321. // }
  322. }