LightningBoltTransformTrackerScript.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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 System.Collections;
  8. using System.Collections.Generic;
  9. using UnityEngine;
  10. namespace DigitalRuby.ThunderAndLightning
  11. {
  12. /// <summary>
  13. /// Lightning bolt transform tracker script, keeps lightning anchored properly between two transforms
  14. /// </summary>
  15. public class LightningBoltTransformTrackerScript : MonoBehaviour
  16. {
  17. /// <summary>The lightning script to track.</summary>
  18. [Tooltip("The lightning script to track.")]
  19. public LightningBoltPrefabScript LightningScript;
  20. /// <summary>The transform to track which will be where the bolts are emitted from.</summary>
  21. [Tooltip("The transform to track which will be where the bolts are emitted from.")]
  22. public Transform StartTarget;
  23. /// <summary>(Optional) The transform to track which will be where the bolts are emitted to. If no end target is specified, lightning will simply move to stay on top of the start target.</summary>
  24. [Tooltip("(Optional) The transform to track which will be where the bolts are emitted to. If no end target is specified, lightning will simply move to stay on top of the start target.")]
  25. public Transform EndTarget;
  26. /// <summary>Scaling limits.</summary>
  27. [SingleLine("Scaling limits.")]
  28. public RangeOfFloats ScaleLimit = new RangeOfFloats { Minimum = 0.1f, Maximum = 10.0f };
  29. private readonly Dictionary<Transform, LightningCustomTransformStateInfo> transformStartPositions = new Dictionary<Transform, LightningCustomTransformStateInfo>();
  30. private void Start()
  31. {
  32. if (LightningScript != null)
  33. {
  34. LightningScript.CustomTransformHandler.RemoveAllListeners();
  35. LightningScript.CustomTransformHandler.AddListener(CustomTransformHandler);
  36. }
  37. }
  38. private static float AngleBetweenVector2(Vector2 vec1, Vector2 vec2)
  39. {
  40. Vector2 diference = (vec2 - vec1).normalized;
  41. return Vector2.Angle(Vector2.right, diference) * Mathf.Sign(vec2.y - vec1.y);
  42. }
  43. private static void UpdateTransform(LightningCustomTransformStateInfo state, LightningBoltPrefabScript script, RangeOfFloats scaleLimit)
  44. {
  45. if (state.Transform == null || state.StartTransform == null)
  46. {
  47. return;
  48. }
  49. else if (state.EndTransform == null)
  50. {
  51. // just put the lightning at the start and be done
  52. state.Transform.position = state.StartTransform.position - state.BoltStartPosition;
  53. return;
  54. }
  55. Quaternion rotation;
  56. if ((script.CameraMode == CameraMode.Auto && script.Camera.orthographic) ||
  57. (script.CameraMode == CameraMode.OrthographicXY))
  58. {
  59. // 2D rotation delta (xy)
  60. float startAngle = AngleBetweenVector2(state.BoltStartPosition, state.BoltEndPosition);
  61. float currentAngle = AngleBetweenVector2(state.StartTransform.position, state.EndTransform.position);
  62. rotation = Quaternion.AngleAxis((currentAngle - startAngle), Vector3.forward);
  63. }
  64. if (script.CameraMode == CameraMode.OrthographicXZ)
  65. {
  66. // 2D rotation delta (xz)
  67. float startAngle = AngleBetweenVector2(new Vector2(state.BoltStartPosition.x, state.BoltStartPosition.z), new Vector2(state.BoltEndPosition.x, state.BoltEndPosition.z));
  68. float currentAngle = AngleBetweenVector2(new Vector2(state.StartTransform.position.x, state.StartTransform.position.z), new Vector2(state.EndTransform.position.x, state.EndTransform.position.z));
  69. rotation = Quaternion.AngleAxis((currentAngle - startAngle), Vector3.up);
  70. }
  71. else
  72. {
  73. // 3D rotation delta
  74. Quaternion look1 = Quaternion.LookRotation((state.BoltEndPosition - state.BoltStartPosition).normalized);
  75. Quaternion look2 = Quaternion.LookRotation((state.EndTransform.position - state.StartTransform.position).normalized);
  76. rotation = look2 * Quaternion.Inverse(look1);
  77. }
  78. state.Transform.rotation = rotation;
  79. // scale based on how much the objects have moved relative to each other
  80. float startDistance = Vector3.Distance(state.BoltStartPosition, state.BoltEndPosition);
  81. float endDistance = Vector3.Distance(state.EndTransform.position, state.StartTransform.position);
  82. float scale = Mathf.Clamp((startDistance < Mathf.Epsilon ? 1.0f : endDistance / startDistance), scaleLimit.Minimum, scaleLimit.Maximum);
  83. state.Transform.localScale = new Vector3(scale, scale, scale);
  84. // anchor lightning to start position and account for rotation and scale
  85. Vector3 offset = rotation * (scale * state.BoltStartPosition);
  86. state.Transform.position = state.StartTransform.position - offset;
  87. }
  88. /// <summary>
  89. ///
  90. /// </summary>
  91. /// <param name="state"></param>
  92. public void CustomTransformHandler(LightningCustomTransformStateInfo state)
  93. {
  94. if (!enabled)
  95. {
  96. return;
  97. }
  98. else if (LightningScript == null)
  99. {
  100. Debug.LogError("LightningScript property must be set to non-null.");
  101. return;
  102. }
  103. else if (state.State == LightningCustomTransformState.Executing)
  104. {
  105. UpdateTransform(state, LightningScript, ScaleLimit);
  106. }
  107. else if (state.State == LightningCustomTransformState.Started)
  108. {
  109. // mark the start and end positions to base rotation and scale changes on
  110. state.StartTransform = StartTarget;
  111. state.EndTransform = EndTarget;
  112. transformStartPositions[transform] = state;
  113. }
  114. else
  115. {
  116. // remove the transform, this bolt is done
  117. transformStartPositions.Remove(transform);
  118. }
  119. }
  120. }
  121. }