ParticleManager.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. //---------------------------------------------------------------------------------
  2. // Ported to the Atomic Game Engine
  3. // Originally written for XNA by Michael Hoffman
  4. // Find the full tutorial at: http://gamedev.tutsplus.com/series/vector-shooter-xna/
  5. //----------------------------------------------------------------------------------
  6. using System;
  7. using AtomicEngine;
  8. namespace AtomicBlaster
  9. {
  10. public class ParticleManager<T>
  11. {
  12. // This delegate will be called for each particle.
  13. private Action<Particle> updateParticle;
  14. private CircularParticleArray particleList;
  15. /// <summary>
  16. /// Allows creation of particles.
  17. /// </summary>
  18. /// <param name="capacity">The maximum number of particles. An array of this size will be pre-allocated.</param>
  19. /// <param name="updateParticle">A delegate that lets you specify custom behaviour for your particles. Called once per particle, per frame.</param>
  20. public ParticleManager(int capacity, Action<Particle> updateParticle)
  21. {
  22. this.updateParticle = updateParticle;
  23. particleList = new CircularParticleArray(capacity);
  24. // Populate the list with empty particle objects, for reuse.
  25. for (int i = 0; i < capacity; i++)
  26. particleList[i] = new Particle();
  27. }
  28. /// <summary>
  29. /// Update particle state, to be called every frame.
  30. /// </summary>
  31. public void Update()
  32. {
  33. int removalCount = 0;
  34. for (int i = 0; i < particleList.Count; i++)
  35. {
  36. var particle = particleList[i];
  37. updateParticle(particle);
  38. particle.PercentLife -= 1f / particle.Duration;
  39. // sift deleted particles to the end of the list
  40. Swap(particleList, i - removalCount, i);
  41. // if the alpha < 0, delete this particle
  42. if (particle.PercentLife < 0)
  43. removalCount++;
  44. }
  45. particleList.Count -= removalCount;
  46. }
  47. private static void Swap(CircularParticleArray list, int index1, int index2)
  48. {
  49. var temp = list[index1];
  50. list[index1] = list[index2];
  51. list[index2] = temp;
  52. }
  53. /// <summary>
  54. /// Draw the particles.
  55. /// </summary>
  56. public void Draw(/*SpriteBatch spriteBatch*/)
  57. {
  58. for (int i = 0; i < particleList.Count; i++)
  59. {
  60. var particle = particleList[i];
  61. Vector2 origin = new Vector2(particle.Texture.Width / 2, particle.Texture.Height / 2);
  62. CustomRenderer.Draw(particle.Texture, particle.Position, particle.Tint, particle.Orientation, origin, particle.Scale, 0);
  63. }
  64. }
  65. public void CreateParticle(CustomSprite texture, Vector2 position, Color tint, float duration, float scale, T state, float theta = 0)
  66. {
  67. CreateParticle(texture, position, tint, duration, new Vector2(scale, scale), state, theta);
  68. }
  69. public void CreateParticle(CustomSprite texture, Vector2 position, Color tint, float duration, Vector2 scale, T state, float theta = 0)
  70. {
  71. Particle particle;
  72. if (particleList.Count == particleList.Capacity)
  73. {
  74. // if the list is full, overwrite the oldest particle, and rotate the circular list
  75. particle = particleList[0];
  76. particleList.Start++;
  77. }
  78. else
  79. {
  80. particle = particleList[particleList.Count];
  81. particleList.Count++;
  82. }
  83. // Create the particle
  84. particle.Texture = texture;
  85. particle.Position = position;
  86. particle.Tint = tint;
  87. particle.Duration = duration;
  88. particle.PercentLife = 1f;
  89. particle.Scale = scale;
  90. particle.Orientation = theta;
  91. particle.State = state;
  92. }
  93. /// <summary>
  94. /// Destroys all particles
  95. /// </summary>
  96. public void Clear()
  97. {
  98. particleList.Count = 0;
  99. }
  100. public int ParticleCount
  101. {
  102. get { return particleList.Count; }
  103. }
  104. public class Particle
  105. {
  106. public CustomSprite Texture;
  107. public Vector2 Position;
  108. public float Orientation;
  109. public Vector2 Scale = Vector2.One;
  110. public Color Tint;
  111. public float Duration;
  112. public float PercentLife = 1f;
  113. public T State;
  114. }
  115. // Represents a circular array with an arbitrary starting point. It's useful for efficiently overwriting
  116. // the oldest particles when the array gets full. Simply overwrite particleList[0] and advance Start.
  117. private class CircularParticleArray
  118. {
  119. private int start;
  120. public int Start
  121. {
  122. get { return start; }
  123. set { start = value % list.Length; }
  124. }
  125. public int Count { get; set; }
  126. public int Capacity { get { return list.Length; } }
  127. private Particle[] list;
  128. public CircularParticleArray() { } // for serialization
  129. public CircularParticleArray(int capacity)
  130. {
  131. list = new Particle[capacity];
  132. }
  133. public Particle this[int i]
  134. {
  135. get { return list[(start + i) % list.Length]; }
  136. set { list[(start + i) % list.Length] = value; }
  137. }
  138. }
  139. }
  140. }