TeleportArc.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. //======= Copyright (c) Valve Corporation, All rights reserved. ===============
  2. //
  3. // Purpose: Displays the arc lines for teleporting and does the traces
  4. //
  5. //=============================================================================
  6. using UnityEngine;
  7. namespace Valve.VR.InteractionSystem
  8. {
  9. //-------------------------------------------------------------------------
  10. public class TeleportArc : MonoBehaviour
  11. {
  12. public int segmentCount = 60;
  13. public float thickness = 0.01f;
  14. [Tooltip("The amount of time in seconds to predict the motion of the projectile.")]
  15. public float arcDuration = 3.0f;
  16. [Tooltip("The amount of time in seconds between each segment of the projectile.")]
  17. public float segmentBreak = 0.025f;
  18. [Tooltip("The speed at which the line segments of the arc move.")]
  19. public float arcSpeed = 0.2f;
  20. public Material material;
  21. [HideInInspector]
  22. public int traceLayerMask = 0;
  23. //Private data
  24. private LineRenderer[] lineRenderers;
  25. private float arcTimeOffset = 0.0f;
  26. private float prevThickness = 0.0f;
  27. private int prevSegmentCount = 0;
  28. private bool showArc = true;
  29. private Vector3 startPos;
  30. private Vector3 projectileVelocity;
  31. private bool useGravity = true;
  32. private Transform arcObjectsTransfrom;
  33. private bool arcInvalid = false;
  34. private float scale = 1;
  35. //-------------------------------------------------
  36. void Start()
  37. {
  38. arcTimeOffset = Time.time;
  39. }
  40. //-------------------------------------------------
  41. void Update()
  42. {
  43. //scale arc to match player scale
  44. scale = Player.instance.transform.lossyScale.x;
  45. if (thickness != prevThickness || segmentCount != prevSegmentCount)
  46. {
  47. CreateLineRendererObjects();
  48. prevThickness = thickness;
  49. prevSegmentCount = segmentCount;
  50. }
  51. }
  52. //-------------------------------------------------
  53. private void CreateLineRendererObjects()
  54. {
  55. //Destroy any existing line renderer objects
  56. if (arcObjectsTransfrom != null)
  57. {
  58. Destroy(arcObjectsTransfrom.gameObject);
  59. }
  60. GameObject arcObjectsParent = new GameObject("ArcObjects");
  61. arcObjectsTransfrom = arcObjectsParent.transform;
  62. arcObjectsTransfrom.SetParent(this.transform);
  63. //Create new line renderer objects
  64. lineRenderers = new LineRenderer[segmentCount];
  65. for (int i = 0; i < segmentCount; ++i)
  66. {
  67. GameObject newObject = new GameObject("LineRenderer_" + i);
  68. newObject.transform.SetParent(arcObjectsTransfrom);
  69. lineRenderers[i] = newObject.AddComponent<LineRenderer>();
  70. lineRenderers[i].receiveShadows = false;
  71. lineRenderers[i].reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off;
  72. lineRenderers[i].lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off;
  73. lineRenderers[i].shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
  74. lineRenderers[i].material = material;
  75. #if (UNITY_5_4)
  76. lineRenderers[i].SetWidth(thickness, thickness);
  77. #else
  78. lineRenderers[i].startWidth = thickness * scale;
  79. lineRenderers[i].endWidth = thickness * scale;
  80. #endif
  81. lineRenderers[i].enabled = false;
  82. }
  83. }
  84. //-------------------------------------------------
  85. public void SetArcData(Vector3 position, Vector3 velocity, bool gravity, bool pointerAtBadAngle)
  86. {
  87. startPos = position;
  88. projectileVelocity = velocity;
  89. useGravity = gravity;
  90. if (arcInvalid && !pointerAtBadAngle)
  91. {
  92. arcTimeOffset = Time.time;
  93. }
  94. arcInvalid = pointerAtBadAngle;
  95. }
  96. //-------------------------------------------------
  97. public void Show()
  98. {
  99. showArc = true;
  100. if (lineRenderers == null)
  101. {
  102. CreateLineRendererObjects();
  103. }
  104. }
  105. //-------------------------------------------------
  106. public void Hide()
  107. {
  108. //Hide the line segments if they were previously being shown
  109. if (showArc)
  110. {
  111. HideLineSegments(0, segmentCount);
  112. }
  113. showArc = false;
  114. }
  115. //-------------------------------------------------
  116. // Draws each segment of the arc individually
  117. //-------------------------------------------------
  118. public bool DrawArc(out RaycastHit hitInfo)
  119. {
  120. float timeStep = arcDuration / segmentCount;
  121. float currentTimeOffset = (Time.time - arcTimeOffset) * arcSpeed;
  122. //Reset the arc time offset when it has gone beyond a segment length
  123. if (currentTimeOffset > (timeStep + segmentBreak))
  124. {
  125. arcTimeOffset = Time.time;
  126. currentTimeOffset = 0.0f;
  127. }
  128. float segmentStartTime = currentTimeOffset;
  129. float arcHitTime = FindProjectileCollision(out hitInfo);
  130. if (arcInvalid)
  131. {
  132. //Only draw first segment
  133. lineRenderers[0].enabled = true;
  134. lineRenderers[0].SetPosition(0, GetArcPositionAtTime(0.0f));
  135. lineRenderers[0].SetPosition(1, GetArcPositionAtTime(arcHitTime < timeStep ? arcHitTime : timeStep));
  136. HideLineSegments(1, segmentCount);
  137. }
  138. else
  139. {
  140. //Draw the first segment outside the loop if needed
  141. int loopStartSegment = 0;
  142. if (segmentStartTime > segmentBreak)
  143. {
  144. float firstSegmentEndTime = currentTimeOffset - segmentBreak;
  145. if (arcHitTime < firstSegmentEndTime)
  146. {
  147. firstSegmentEndTime = arcHitTime;
  148. }
  149. DrawArcSegment(0, 0.0f, firstSegmentEndTime);
  150. loopStartSegment = 1;
  151. }
  152. bool stopArc = false;
  153. int currentSegment = 0;
  154. if (segmentStartTime < arcHitTime)
  155. {
  156. for (currentSegment = loopStartSegment; currentSegment < segmentCount; ++currentSegment)
  157. {
  158. //Clamp the segment end time to the arc duration
  159. float segmentEndTime = segmentStartTime + timeStep;
  160. if (segmentEndTime >= arcDuration)
  161. {
  162. segmentEndTime = arcDuration;
  163. stopArc = true;
  164. }
  165. if (segmentEndTime >= arcHitTime)
  166. {
  167. segmentEndTime = arcHitTime;
  168. stopArc = true;
  169. }
  170. DrawArcSegment(currentSegment, segmentStartTime, segmentEndTime);
  171. segmentStartTime += timeStep + segmentBreak;
  172. //If the previous end time or the next start time is beyond the duration then stop the arc
  173. if (stopArc || segmentStartTime >= arcDuration || segmentStartTime >= arcHitTime)
  174. {
  175. break;
  176. }
  177. }
  178. }
  179. else
  180. {
  181. currentSegment--;
  182. }
  183. //Hide the rest of the line segments
  184. HideLineSegments(currentSegment + 1, segmentCount);
  185. }
  186. return arcHitTime != float.MaxValue;
  187. }
  188. //-------------------------------------------------
  189. private void DrawArcSegment(int index, float startTime, float endTime)
  190. {
  191. lineRenderers[index].enabled = true;
  192. lineRenderers[index].SetPosition(0, GetArcPositionAtTime(startTime));
  193. lineRenderers[index].SetPosition(1, GetArcPositionAtTime(endTime));
  194. }
  195. //-------------------------------------------------
  196. public void SetColor(Color color)
  197. {
  198. for (int i = 0; i < segmentCount; ++i)
  199. {
  200. #if (UNITY_5_4)
  201. lineRenderers[i].SetColors(color, color);
  202. #else
  203. lineRenderers[i].startColor = color;
  204. lineRenderers[i].endColor = color;
  205. #endif
  206. }
  207. }
  208. //-------------------------------------------------
  209. private float FindProjectileCollision(out RaycastHit hitInfo)
  210. {
  211. float timeStep = arcDuration / segmentCount;
  212. float segmentStartTime = 0.0f;
  213. hitInfo = new RaycastHit();
  214. Vector3 segmentStartPos = GetArcPositionAtTime(segmentStartTime);
  215. for (int i = 0; i < segmentCount; ++i)
  216. {
  217. float segmentEndTime = segmentStartTime + timeStep;
  218. Vector3 segmentEndPos = GetArcPositionAtTime(segmentEndTime);
  219. if (Physics.Linecast(segmentStartPos, segmentEndPos, out hitInfo, traceLayerMask))
  220. {
  221. if (hitInfo.collider.GetComponent<IgnoreTeleportTrace>() == null)
  222. {
  223. Util.DrawCross(hitInfo.point, Color.red, 0.5f);
  224. float segmentDistance = Vector3.Distance(segmentStartPos, segmentEndPos);
  225. float hitTime = segmentStartTime + (timeStep * (hitInfo.distance / segmentDistance));
  226. return hitTime;
  227. }
  228. }
  229. segmentStartTime = segmentEndTime;
  230. segmentStartPos = segmentEndPos;
  231. }
  232. return float.MaxValue;
  233. }
  234. //-------------------------------------------------
  235. public Vector3 GetArcPositionAtTime(float time)
  236. {
  237. Vector3 gravity = useGravity ? Physics.gravity : Vector3.zero;
  238. Vector3 arcPos = startPos + ((projectileVelocity * time) + (0.5f * time * time) * gravity) * scale;
  239. return arcPos;
  240. }
  241. //-------------------------------------------------
  242. private void HideLineSegments(int startSegment, int endSegment)
  243. {
  244. if (lineRenderers != null)
  245. {
  246. for (int i = startSegment; i < endSegment; ++i)
  247. {
  248. lineRenderers[i].enabled = false;
  249. }
  250. }
  251. }
  252. }
  253. }