CircleContainerModifier.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // Copyright (c) Craftwork Games. All rights reserved.
  2. // Licensed under the MIT license.
  3. // See LICENSE file in the project root for full license information.
  4. using System;
  5. using Microsoft.Xna.Framework;
  6. using MonoGame.Extended.Particles.Data;
  7. namespace MonoGame.Extended.Particles.Modifiers.Containers;
  8. /// <summary>
  9. /// A modifier that constrains particles within or outside of a circular boundary.
  10. /// </summary>
  11. /// <remarks>
  12. /// The <see cref="CircleContainerModifier"/> keeps particles either inside or outside a circular area, reflecting them
  13. /// at the boundary based on a configurable restitution coefficient. The circle is centered at each particle's trigger
  14. /// position (where it was emitted), creating local containment areas.
  15. /// </remarks>
  16. public class CircleContainerModifier : Modifier
  17. {
  18. /// <summary>
  19. /// The radius of the circular container.
  20. /// </summary>
  21. public float Radius;
  22. /// <summary>
  23. /// Indicates whether particles should be contained inside the circle.
  24. /// </summary>
  25. /// <remarks>
  26. /// <list type="bullet">
  27. /// <item>
  28. /// When <see langword="true"/>, particles are kept inside the circle (bouncing inward at the boundary).
  29. /// </item>
  30. /// <item>
  31. /// When <see langword="false"/>, particles are kept outside the circle (bouncing outward at the boundary).
  32. /// </item>
  33. /// </list>
  34. ///
  35. /// The default value is <see langword="true"/>.
  36. /// </remarks>
  37. public bool Inside = true;
  38. /// <summary>
  39. /// Gets or sets the coefficient of restitution (bounciness) for particle collisions with the boundary.
  40. /// </summary>
  41. /// <remarks>
  42. /// <list type="bullet">
  43. /// <item>
  44. /// A value of 1.0 creates a perfectly elastic collision where particles maintain their energy.
  45. /// </item>
  46. /// <item>
  47. /// Values less than 1.0 create inelastic collisions where particles lose energy with each bounce.
  48. /// </item>
  49. /// <item>
  50. /// Values greater than 1.0 create super-elastic collisions where particles gain energy.
  51. /// </item>
  52. /// </list>
  53. ///
  54. /// The default value is 1.0.
  55. /// </remarks>
  56. public float RestitutionCoefficient = 1;
  57. /// <summary>
  58. /// Updates all particles by constraining them to the circular boundary.
  59. /// </summary>
  60. /// <inheritdoc/>
  61. public override unsafe void Update(float elapsedSeconds, ParticleIterator iterator)
  62. {
  63. if (!Enabled) { return; }
  64. float radiusSq = Radius * Radius;
  65. while (iterator.HasNext)
  66. {
  67. Particle* particle = iterator.Next();
  68. Vector2 localPos;
  69. localPos.X = particle->Position[0] - particle->TriggeredPos[0];
  70. localPos.Y = particle->Position[1] - particle->TriggeredPos[1];
  71. float distSq = localPos.LengthSquared();
  72. Vector2 normal = Vector2.Normalize(localPos);
  73. if (Inside)
  74. {
  75. if (distSq < radiusSq) { continue; }
  76. SetReflected(distSq, particle, normal);
  77. }
  78. else
  79. {
  80. if (distSq > radiusSq) { continue; }
  81. SetReflected(distSq, particle, -normal);
  82. }
  83. }
  84. }
  85. private unsafe void SetReflected(float distSq, Particle* particle, Vector2 normal)
  86. {
  87. float dist = MathF.Sqrt(distSq);
  88. float d = dist - Radius;
  89. float twoRestDot = 2 * RestitutionCoefficient *
  90. Vector2.Dot(new Vector2(particle->Velocity[0], particle->Velocity[1]), normal);
  91. particle->Velocity[0] -= twoRestDot * normal.X;
  92. particle->Velocity[1] -= twoRestDot * normal.Y;
  93. // exact computation requires sqrt or goniometrics
  94. particle->Position[0] -= normal.X * d;
  95. particle->Position[1] -= normal.Y * d;
  96. }
  97. }