LightningSplineScript.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. //
  2. // Procedural Lightning for Unity
  3. // (c) 2015 Digital Ruby, LLC
  4. // Source code may be used for personal or commercial projects.
  5. // Source code may NOT be redistributed or sold.
  6. //
  7. using UnityEngine;
  8. using System.Collections;
  9. using System.Collections.Generic;
  10. namespace DigitalRuby.ThunderAndLightning
  11. {
  12. /// <summary>
  13. /// Lightning bolt spline script, helps lightning curve around path points
  14. /// </summary>
  15. public class LightningSplineScript : LightningBoltPathScriptBase
  16. {
  17. /// <summary>
  18. /// For performance, cap generations
  19. /// </summary>
  20. public const int MaxSplineGenerations = 5;
  21. /// <summary>The distance hint for each spline segment. Set to &lt;= 0 to use the generations to determine how many spline segments to use. If &gt; 0, it will be divided by Generations before being applied. This value is a guideline and is approximate, and not uniform on the spline.</summary>
  22. [Header("Lightning Spline Properties")]
  23. [Tooltip("The distance hint for each spline segment. Set to <= 0 to use the generations to determine how many spline segments to use. " +
  24. "If > 0, it will be divided by Generations before being applied. This value is a guideline and is approximate, and not uniform on the spline.")]
  25. public float DistancePerSegmentHint = 0.0f;
  26. private readonly List<Vector3> prevSourcePoints = new List<Vector3>(new Vector3[] { Vector3.zero });
  27. private readonly List<Vector3> sourcePoints = new List<Vector3>();
  28. private List<Vector3> savedSplinePoints = new List<Vector3>();
  29. private int previousGenerations = -1;
  30. private float previousDistancePerSegment = -1.0f;
  31. private bool SourceChanged()
  32. {
  33. if (sourcePoints.Count != prevSourcePoints.Count)
  34. {
  35. return true;
  36. }
  37. for (int i = 0; i < sourcePoints.Count; i++)
  38. {
  39. if (sourcePoints[i] != prevSourcePoints[i])
  40. {
  41. return true;
  42. }
  43. }
  44. return false;
  45. }
  46. /// <summary>
  47. /// Start
  48. /// </summary>
  49. protected override void Start()
  50. {
  51. base.Start();
  52. }
  53. /// <summary>
  54. /// Update
  55. /// </summary>
  56. protected override void Update()
  57. {
  58. base.Update();
  59. }
  60. /// <summary>
  61. /// Create a lightning bolt
  62. /// </summary>
  63. /// <param name="parameters">Parameters</param>
  64. public override void CreateLightningBolt(LightningBoltParameters parameters)
  65. {
  66. if (LightningPath == null)
  67. {
  68. return;
  69. }
  70. sourcePoints.Clear();
  71. try
  72. {
  73. foreach (GameObject obj in LightningPath)
  74. {
  75. if (obj != null)
  76. {
  77. sourcePoints.Add(obj.transform.position);
  78. }
  79. }
  80. }
  81. catch (System.NullReferenceException)
  82. {
  83. return;
  84. }
  85. if (sourcePoints.Count < PathGenerator.MinPointsForSpline)
  86. {
  87. Debug.LogError("To create spline lightning, you need a lightning path with at least " + PathGenerator.MinPointsForSpline + " points.");
  88. }
  89. else
  90. {
  91. Generations = parameters.Generations = Mathf.Clamp(Generations, 1, MaxSplineGenerations);
  92. parameters.Points.Clear();
  93. if (previousGenerations != Generations || previousDistancePerSegment != DistancePerSegmentHint || SourceChanged())
  94. {
  95. previousGenerations = Generations;
  96. previousDistancePerSegment = DistancePerSegmentHint;
  97. PopulateSpline(parameters.Points, sourcePoints, Generations, DistancePerSegmentHint, Camera);
  98. prevSourcePoints.Clear();
  99. prevSourcePoints.AddRange(sourcePoints);
  100. savedSplinePoints.Clear();
  101. savedSplinePoints.AddRange(parameters.Points);
  102. }
  103. else
  104. {
  105. parameters.Points.AddRange(savedSplinePoints);
  106. }
  107. parameters.SmoothingFactor = (parameters.Points.Count - 1) / sourcePoints.Count;
  108. base.CreateLightningBolt(parameters);
  109. }
  110. }
  111. /// <summary>
  112. /// Create a new lightning bolt parameters instance or get from cache
  113. /// </summary>
  114. /// <returns>LightningBoltParameters</returns>
  115. protected override LightningBoltParameters OnCreateParameters()
  116. {
  117. LightningBoltParameters p = LightningBoltParameters.GetOrCreateParameters();
  118. p.Generator = LightningGeneratorPath.PathGeneratorInstance;
  119. return p;
  120. }
  121. /// <summary>
  122. /// Triggers lightning that follows a set of points, rather than the standard lightning bolt that goes between two points.
  123. /// </summary>
  124. /// <param name="points">Points to follow</param>
  125. /// <param name="spline">Whether to spline the lightning through the points or not</param>
  126. public void Trigger(List<Vector3> points, bool spline)
  127. {
  128. if (points.Count < 2)
  129. {
  130. return;
  131. }
  132. Generations = Mathf.Clamp(Generations, 1, MaxSplineGenerations);
  133. LightningBoltParameters parameters = CreateParameters();
  134. parameters.Points.Clear();
  135. if (spline && points.Count > 3)
  136. {
  137. LightningSplineScript.PopulateSpline(parameters.Points, points, Generations, DistancePerSegmentHint, Camera);
  138. parameters.SmoothingFactor = (parameters.Points.Count - 1) / points.Count;
  139. }
  140. else
  141. {
  142. parameters.Points.AddRange(points);
  143. parameters.SmoothingFactor = 1;
  144. }
  145. base.CreateLightningBolt(parameters);
  146. CreateLightningBoltsNow();
  147. }
  148. /// <summary>
  149. /// Populate a list of spline points from source points
  150. /// </summary>
  151. /// <param name="splinePoints">List to fill with spline points</param>
  152. /// <param name="sourcePoints">Source points</param>
  153. /// <param name="generations">Generations</param>
  154. /// <param name="distancePerSegmentHit">Distance per segment hint - if non-zero, attempts to maintain this distance between spline points.</param>
  155. /// <param name="camera">Optional camera</param>
  156. public static void PopulateSpline(List<Vector3> splinePoints, List<Vector3> sourcePoints, int generations, float distancePerSegmentHit, Camera camera)
  157. {
  158. splinePoints.Clear();
  159. PathGenerator.Is2D = (camera != null && camera.orthographic);
  160. if (distancePerSegmentHit > 0.0f)
  161. {
  162. PathGenerator.CreateSplineWithSegmentDistance(splinePoints, sourcePoints, distancePerSegmentHit / generations, false);
  163. }
  164. else
  165. {
  166. PathGenerator.CreateSpline(splinePoints, sourcePoints, sourcePoints.Count * generations * generations, false);
  167. }
  168. }
  169. }
  170. }