TeleportArc.cs 8.3 KB

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