ParticleDemo.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // ParticleDemo.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.Linq;
  13. using System.Text;
  14. using Microsoft.Xna.Framework;
  15. using Microsoft.Xna.Framework.Graphics;
  16. using SkinnedModel;
  17. #endregion
  18. namespace XnaGraphicsDemo
  19. {
  20. /// <summary>
  21. /// Demo shows how to use SpriteBatch.
  22. /// </summary>
  23. class ParticleDemo : MenuComponent
  24. {
  25. const int MaxParticles = 5000;
  26. struct Particle
  27. {
  28. public Vector2 Position;
  29. public Vector2 Velocity;
  30. public float Size;
  31. public float Rotation;
  32. public float Spin;
  33. public Color Color;
  34. }
  35. Particle[] particles = new Particle[MaxParticles];
  36. int firstParticle;
  37. int particleCount;
  38. FloatMenuEntry spawnRate;
  39. float spawnCounter;
  40. Texture2D cat;
  41. Random random = new Random();
  42. /// <summary>
  43. /// Constructor.
  44. /// </summary>
  45. public ParticleDemo(DemoGame game)
  46. : base(game)
  47. {
  48. Entries.Add(spawnRate = new FloatMenuEntry() { Text = "spawn rate" });
  49. // This menu option for changing the resolution is currently disabled,
  50. // because the image scaler feature is not yet implemented in the CTP release.
  51. /*
  52. Entries.Add(new ResolutionMenu(game.graphics));
  53. */
  54. Entries.Add(new MenuEntry
  55. {
  56. Text = "back",
  57. Clicked = delegate
  58. {
  59. // Before we quit back out of this menu, reset back to the default resolution.
  60. if (game.Graphics.PreferredBackBufferWidth != 480)
  61. {
  62. game.Graphics.PreferredBackBufferWidth = 480;
  63. game.Graphics.PreferredBackBufferHeight = 800;
  64. game.Graphics.ApplyChanges();
  65. }
  66. Game.SetActiveMenu(0);
  67. } });
  68. }
  69. /// <summary>
  70. /// Resets the menu state.
  71. /// </summary>
  72. public override void Reset()
  73. {
  74. firstParticle = 0;
  75. particleCount = 0;
  76. spawnRate.Value = 0.2f;
  77. base.Reset();
  78. }
  79. /// <summary>
  80. /// Loads content for this demo.
  81. /// </summary>
  82. protected override void LoadContent()
  83. {
  84. cat = Game.Content.Load<Texture2D>("cat");
  85. }
  86. /// <summary>
  87. /// Updates the particle system.
  88. /// </summary>
  89. public override void Update(GameTime gameTime)
  90. {
  91. int i = firstParticle;
  92. for (int j = particleCount; j > 0; j--)
  93. {
  94. // Move a particle.
  95. particles[i].Position += particles[i].Velocity;
  96. particles[i].Rotation += particles[i].Spin;
  97. particles[i].Velocity.Y += 0.1f;
  98. // Retire old particles?
  99. const float borderPadding = 96;
  100. if (i == firstParticle)
  101. {
  102. if ((particles[i].Position.X < -borderPadding) ||
  103. (particles[i].Position.X > 480 + borderPadding) ||
  104. (particles[i].Position.Y < -borderPadding) ||
  105. (particles[i].Position.Y > 800 + borderPadding))
  106. {
  107. if (++firstParticle >= MaxParticles)
  108. firstParticle = 0;
  109. particleCount--;
  110. }
  111. }
  112. if (++i >= MaxParticles)
  113. i = 0;
  114. }
  115. // Spawn new particles?
  116. spawnCounter += spawnRate.Value * 10;
  117. while (spawnCounter > 1)
  118. {
  119. SpawnParticle(null);
  120. spawnCounter--;
  121. }
  122. base.Update(gameTime);
  123. }
  124. /// <summary>
  125. /// Helper creates a new cat particle.
  126. /// </summary>
  127. void SpawnParticle(Vector2? position)
  128. {
  129. if (particleCount >= MaxParticles)
  130. return;
  131. int i = firstParticle + particleCount;
  132. if (i >= MaxParticles)
  133. i -= MaxParticles;
  134. particles[i].Position = position ?? new Vector2((float)random.NextDouble() * 480, (float)random.NextDouble() * 800);
  135. particles[i].Velocity = new Vector2((float)random.NextDouble() - 0.5f, (float)random.NextDouble() - 0.5f) * 10f;
  136. particles[i].Size = (float)random.NextDouble() * 0.5f + 0.5f;
  137. particles[i].Rotation = 0;
  138. particles[i].Spin = ((float)random.NextDouble() - 0.5f) * 0.1f;
  139. if (position.HasValue)
  140. {
  141. // Explicitly positioned particles have no tint.
  142. particles[i].Color = Color.White;
  143. }
  144. else
  145. {
  146. // Randomly positioned particles have random tint colors.
  147. byte r = (byte)(128 + random.NextDouble() * 127);
  148. byte g = (byte)(128 + random.NextDouble() * 127);
  149. byte b = (byte)(128 + random.NextDouble() * 127);
  150. particles[i].Color = new Color(r, g, b);
  151. }
  152. particleCount++;
  153. }
  154. /// <summary>
  155. /// Draws the cat particle system.
  156. /// </summary>
  157. public override void Draw(GameTime gameTime)
  158. {
  159. DrawTitle("particles", Color.CornflowerBlue, Color.Lerp(Color.Blue, Color.CornflowerBlue, 0.85f));
  160. SpriteBatch.Begin(0, null, null, null, null, null, Game.ScaleMatrix);
  161. Vector2 origin = new Vector2(cat.Width, cat.Height) / 2;
  162. int i = firstParticle + particleCount - 1;
  163. if (i >= MaxParticles)
  164. i -= MaxParticles;
  165. for (int j = 0; j < particleCount; j++)
  166. {
  167. SpriteBatch.Draw(cat, particles[i].Position, null, particles[i].Color, particles[i].Rotation, origin, particles[i].Size, 0, 0);
  168. if (--i < 0)
  169. i = MaxParticles - 1;
  170. }
  171. SpriteBatch.End();
  172. base.Draw(gameTime);
  173. }
  174. /// <summary>
  175. /// Dragging on the menu background creates new particles.
  176. /// </summary>
  177. protected override void OnDrag(Vector2 delta)
  178. {
  179. SpawnParticle(LastTouchPoint);
  180. }
  181. /// <summary>
  182. /// Custom menu entry subclass for cycling through different backbuffer resolutions.
  183. /// </summary>
  184. class ResolutionMenu : MenuEntry
  185. {
  186. GraphicsDeviceManager graphics;
  187. public ResolutionMenu(GraphicsDeviceManager graphics)
  188. {
  189. this.graphics = graphics;
  190. }
  191. public override string Text
  192. {
  193. get { return string.Format("{0}x{1}", graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight); }
  194. set { }
  195. }
  196. public override void OnClicked()
  197. {
  198. switch (graphics.PreferredBackBufferWidth)
  199. {
  200. case 480:
  201. graphics.PreferredBackBufferWidth = 360;
  202. graphics.PreferredBackBufferHeight = 600;
  203. break;
  204. case 360:
  205. graphics.PreferredBackBufferWidth = 240;
  206. graphics.PreferredBackBufferHeight = 400;
  207. break;
  208. case 240:
  209. graphics.PreferredBackBufferWidth = 480;
  210. graphics.PreferredBackBufferHeight = 800;
  211. break;
  212. }
  213. graphics.ApplyChanges();
  214. base.OnClicked();
  215. }
  216. }
  217. }
  218. }