ParticlesFollowBezier.cs 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. namespace BezierSolution
  4. {
  5. [ExecuteInEditMode]
  6. public class ParticlesFollowBezier : MonoBehaviour
  7. {
  8. private const int MAX_PARTICLE_COUNT = 25000;
  9. public enum FollowMode { Relaxed, Strict };
  10. public BezierSpline spline;
  11. public FollowMode followMode = FollowMode.Relaxed;
  12. private Transform cachedTransform;
  13. private ParticleSystem cachedPS;
  14. private ParticleSystem.MainModule cachedMainModule;
  15. private ParticleSystem.Particle[] particles;
  16. private List<Vector4> particleData;
  17. private void Awake()
  18. {
  19. cachedTransform = transform;
  20. cachedPS = GetComponent<ParticleSystem>();
  21. cachedMainModule = cachedPS.main;
  22. particles = new ParticleSystem.Particle[cachedMainModule.maxParticles];
  23. if( followMode == FollowMode.Relaxed )
  24. particleData = new List<Vector4>( particles.Length );
  25. }
  26. #if UNITY_EDITOR
  27. private void OnEnable()
  28. {
  29. Awake();
  30. }
  31. #endif
  32. private void LateUpdate()
  33. {
  34. if( spline == null || cachedPS == null )
  35. return;
  36. if( particles.Length < cachedMainModule.maxParticles && particles.Length < MAX_PARTICLE_COUNT )
  37. particles = new ParticleSystem.Particle[Mathf.Min( cachedMainModule.maxParticles, MAX_PARTICLE_COUNT )];
  38. bool isLocalSpace = cachedMainModule.simulationSpace != ParticleSystemSimulationSpace.World;
  39. int aliveParticles = cachedPS.GetParticles( particles );
  40. if( followMode == FollowMode.Relaxed )
  41. {
  42. if( particleData == null )
  43. particleData = new List<Vector4>( particles.Length );
  44. cachedPS.GetCustomParticleData( particleData, ParticleSystemCustomData.Custom1 );
  45. // Credit: https://forum.unity3d.com/threads/access-to-the-particle-system-lifecycle-events.328918/#post-2295977
  46. for( int i = 0; i < aliveParticles; i++ )
  47. {
  48. Vector4 particleDat = particleData[i];
  49. Vector3 point = spline.GetPoint( 1f - ( particles[i].remainingLifetime / particles[i].startLifetime ) );
  50. if( isLocalSpace )
  51. point = cachedTransform.InverseTransformPoint( point );
  52. // Move particles alongside the spline
  53. if( particleDat.w != 0f )
  54. particles[i].position += point - (Vector3) particleDat;
  55. particleDat = point;
  56. particleDat.w = 1f;
  57. particleData[i] = particleDat;
  58. }
  59. cachedPS.SetCustomParticleData( particleData, ParticleSystemCustomData.Custom1 );
  60. }
  61. else
  62. {
  63. Vector3 deltaPosition = cachedTransform.position - spline.GetPoint( 0f );
  64. for( int i = 0; i < aliveParticles; i++ )
  65. {
  66. Vector3 point = spline.GetPoint( 1f - ( particles[i].remainingLifetime / particles[i].startLifetime ) ) + deltaPosition;
  67. if( isLocalSpace )
  68. point = cachedTransform.InverseTransformPoint( point );
  69. particles[i].position = point;
  70. }
  71. }
  72. cachedPS.SetParticles( particles, aliveParticles );
  73. }
  74. }
  75. }