暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ParticleControlPlayable.cs 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. using System;
  2. using UnityEngine.Playables;
  3. namespace UnityEngine.Timeline
  4. {
  5. /// <summary>
  6. /// Playable that synchronizes a particle system simulation.
  7. /// </summary>
  8. public class ParticleControlPlayable : PlayableBehaviour
  9. {
  10. const float kUnsetTime = float.MaxValue;
  11. float m_LastPlayableTime = kUnsetTime;
  12. float m_LastParticleTime = kUnsetTime;
  13. uint m_RandomSeed = 1;
  14. /// <summary>
  15. /// Creates a Playable with a ParticleControlPlayable behaviour attached
  16. /// </summary>
  17. /// <param name="graph">The PlayableGraph to inject the Playable into.</param>
  18. /// <param name="component">The particle systtem to control</param>
  19. /// <param name="randomSeed">A random seed to use for particle simulation</param>
  20. /// <returns>Returns the created Playable.</returns>
  21. public static ScriptPlayable<ParticleControlPlayable> Create(PlayableGraph graph, ParticleSystem component, uint randomSeed)
  22. {
  23. if (component == null)
  24. return ScriptPlayable<ParticleControlPlayable>.Null;
  25. var handle = ScriptPlayable<ParticleControlPlayable>.Create(graph);
  26. handle.GetBehaviour().Initialize(component, randomSeed);
  27. return handle;
  28. }
  29. /// <summary>
  30. /// The particle system to control
  31. /// </summary>
  32. public ParticleSystem particleSystem { get; private set; }
  33. /// <summary>
  34. /// Initializes the behaviour with a particle system and random seed.
  35. /// </summary>
  36. /// <param name="ps"></param>
  37. /// <param name="randomSeed"></param>
  38. public void Initialize(ParticleSystem ps, uint randomSeed)
  39. {
  40. m_RandomSeed = Math.Max(1, randomSeed);
  41. particleSystem = ps;
  42. SetRandomSeed(particleSystem, m_RandomSeed);
  43. #if UNITY_EDITOR
  44. if (!Application.isPlaying && UnityEditor.PrefabUtility.IsPartOfPrefabInstance(ps))
  45. UnityEditor.PrefabUtility.prefabInstanceUpdated += OnPrefabUpdated;
  46. #endif
  47. }
  48. #if UNITY_EDITOR
  49. /// <summary>
  50. /// This function is called when the Playable that owns the PlayableBehaviour is destroyed.
  51. /// </summary>
  52. /// <param name="playable">The playable this behaviour is attached to.</param>
  53. public override void OnPlayableDestroy(Playable playable)
  54. {
  55. if (!Application.isPlaying)
  56. UnityEditor.PrefabUtility.prefabInstanceUpdated -= OnPrefabUpdated;
  57. }
  58. void OnPrefabUpdated(GameObject go)
  59. {
  60. // When the instance is updated from, this will cause the next evaluate to resimulate.
  61. if (UnityEditor.PrefabUtility.GetRootGameObject(particleSystem) == go)
  62. m_LastPlayableTime = kUnsetTime;
  63. }
  64. #endif
  65. static void SetRandomSeed(ParticleSystem particleSystem, uint randomSeed)
  66. {
  67. if (particleSystem == null)
  68. return;
  69. particleSystem.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
  70. if (particleSystem.useAutoRandomSeed)
  71. {
  72. particleSystem.useAutoRandomSeed = false;
  73. particleSystem.randomSeed = randomSeed;
  74. }
  75. for (int i = 0; i < particleSystem.subEmitters.subEmittersCount; i++)
  76. {
  77. SetRandomSeed(particleSystem.subEmitters.GetSubEmitterSystem(i), ++randomSeed);
  78. }
  79. }
  80. /// <summary>
  81. /// This function is called during the PrepareFrame phase of the PlayableGraph.
  82. /// </summary>
  83. /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param>
  84. /// <param name="data">A FrameData structure that contains information about the current frame context.</param>
  85. public override void PrepareFrame(Playable playable, FrameData data)
  86. {
  87. if (particleSystem == null || !particleSystem.gameObject.activeInHierarchy)
  88. {
  89. // case 1212943
  90. m_LastPlayableTime = kUnsetTime;
  91. return;
  92. }
  93. var time = (float)playable.GetTime();
  94. var particleTime = particleSystem.time;
  95. // if particle system time has changed externally, a re-sync is needed
  96. if (m_LastPlayableTime > time || !Mathf.Approximately(particleTime, m_LastParticleTime))
  97. Simulate(time, true);
  98. else if (m_LastPlayableTime < time)
  99. Simulate(time - m_LastPlayableTime, false);
  100. m_LastPlayableTime = time;
  101. m_LastParticleTime = particleSystem.time;
  102. }
  103. /// <summary>
  104. /// This function is called when the Playable play state is changed to Playables.PlayState.Playing.
  105. /// </summary>
  106. /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param>
  107. /// <param name="info">A FrameData structure that contains information about the current frame context.</param>
  108. public override void OnBehaviourPlay(Playable playable, FrameData info)
  109. {
  110. m_LastPlayableTime = kUnsetTime;
  111. }
  112. /// <summary>
  113. /// This function is called when the Playable play state is changed to PlayState.Paused.
  114. /// </summary>
  115. /// <param name="playable">The playable this behaviour is attached to.</param>
  116. /// <param name="info">A FrameData structure that contains information about the current frame context.</param>
  117. public override void OnBehaviourPause(Playable playable, FrameData info)
  118. {
  119. m_LastPlayableTime = kUnsetTime;
  120. }
  121. private void Simulate(float time, bool restart)
  122. {
  123. const bool withChildren = false;
  124. const bool fixedTimeStep = false;
  125. float maxTime = Time.maximumDeltaTime;
  126. if (restart)
  127. particleSystem.Simulate(0, withChildren, true, fixedTimeStep);
  128. // simulating by too large a time-step causes sub-emitters not to work, and loops not to
  129. // simulate correctly
  130. while (time > maxTime)
  131. {
  132. particleSystem.Simulate(maxTime, withChildren, false, fixedTimeStep);
  133. time -= maxTime;
  134. }
  135. if (time > 0)
  136. particleSystem.Simulate(time, withChildren, false, fixedTimeStep);
  137. }
  138. }
  139. }