Assignment for RMIT Mixed Reality in 2020
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.

1151 lines
33 KiB

  1. //======= Copyright (c) Valve Corporation, All rights reserved. ===============
  2. //
  3. // Purpose: Handles all the teleport logic
  4. //
  5. //=============================================================================
  6. using UnityEngine;
  7. using UnityEngine.Events;
  8. using System.Collections;
  9. namespace Valve.VR.InteractionSystem
  10. {
  11. //-------------------------------------------------------------------------
  12. public class Teleport : MonoBehaviour
  13. {
  14. public LayerMask traceLayerMask;
  15. public LayerMask floorFixupTraceLayerMask;
  16. public float floorFixupMaximumTraceDistance = 1.0f;
  17. public Material areaVisibleMaterial;
  18. public Material areaLockedMaterial;
  19. public Material areaHighlightedMaterial;
  20. public Material pointVisibleMaterial;
  21. public Material pointLockedMaterial;
  22. public Material pointHighlightedMaterial;
  23. public Transform destinationReticleTransform;
  24. public Transform invalidReticleTransform;
  25. public GameObject playAreaPreviewCorner;
  26. public GameObject playAreaPreviewSide;
  27. public Color pointerValidColor;
  28. public Color pointerInvalidColor;
  29. public Color pointerLockedColor;
  30. public bool showPlayAreaMarker = true;
  31. public float teleportFadeTime = 0.1f;
  32. public float meshFadeTime = 0.2f;
  33. public float arcDistance = 10.0f;
  34. [Header( "Effects" )]
  35. public Transform onActivateObjectTransform;
  36. public Transform onDeactivateObjectTransform;
  37. public float activateObjectTime = 1.0f;
  38. public float deactivateObjectTime = 1.0f;
  39. [Header( "Audio Sources" )]
  40. public AudioSource pointerAudioSource;
  41. public AudioSource loopingAudioSource;
  42. public AudioSource headAudioSource;
  43. public AudioSource reticleAudioSource;
  44. [Header( "Sounds" )]
  45. public AudioClip teleportSound;
  46. public AudioClip pointerStartSound;
  47. public AudioClip pointerLoopSound;
  48. public AudioClip pointerStopSound;
  49. public AudioClip goodHighlightSound;
  50. public AudioClip badHighlightSound;
  51. [Header( "Debug" )]
  52. public bool debugFloor = false;
  53. public bool showOffsetReticle = false;
  54. public Transform offsetReticleTransform;
  55. public MeshRenderer floorDebugSphere;
  56. public LineRenderer floorDebugLine;
  57. private LineRenderer pointerLineRenderer;
  58. private GameObject teleportPointerObject;
  59. private Transform pointerStartTransform;
  60. private Hand pointerHand = null;
  61. private Player player = null;
  62. private TeleportArc teleportArc = null;
  63. private bool visible = false;
  64. private TeleportMarkerBase[] teleportMarkers;
  65. private TeleportMarkerBase pointedAtTeleportMarker;
  66. private TeleportMarkerBase teleportingToMarker;
  67. private Vector3 pointedAtPosition;
  68. private Vector3 prevPointedAtPosition;
  69. private bool teleporting = false;
  70. private float currentFadeTime = 0.0f;
  71. private float meshAlphaPercent = 1.0f;
  72. private float pointerShowStartTime = 0.0f;
  73. private float pointerHideStartTime = 0.0f;
  74. private bool meshFading = false;
  75. private float fullTintAlpha;
  76. private float invalidReticleMinScale = 0.2f;
  77. private float invalidReticleMaxScale = 1.0f;
  78. private float invalidReticleMinScaleDistance = 0.4f;
  79. private float invalidReticleMaxScaleDistance = 2.0f;
  80. private Vector3 invalidReticleScale = Vector3.one;
  81. private Quaternion invalidReticleTargetRotation = Quaternion.identity;
  82. private Transform playAreaPreviewTransform;
  83. private Transform[] playAreaPreviewCorners;
  84. private Transform[] playAreaPreviewSides;
  85. private float loopingAudioMaxVolume = 0.0f;
  86. private Coroutine hintCoroutine = null;
  87. private bool originalHoverLockState = false;
  88. private Interactable originalHoveringInteractable = null;
  89. private AllowTeleportWhileAttachedToHand allowTeleportWhileAttached = null;
  90. private Vector3 startingFeetOffset = Vector3.zero;
  91. private bool movedFeetFarEnough = false;
  92. SteamVR_Events.Action chaperoneInfoInitializedAction;
  93. // Events
  94. public static SteamVR_Events.Event< float > ChangeScene = new SteamVR_Events.Event< float >();
  95. public static SteamVR_Events.Action< float > ChangeSceneAction( UnityAction< float > action ) { return new SteamVR_Events.Action< float >( ChangeScene, action ); }
  96. public static SteamVR_Events.Event< TeleportMarkerBase > Player = new SteamVR_Events.Event< TeleportMarkerBase >();
  97. public static SteamVR_Events.Action< TeleportMarkerBase > PlayerAction( UnityAction< TeleportMarkerBase > action ) { return new SteamVR_Events.Action< TeleportMarkerBase >( Player, action ); }
  98. public static SteamVR_Events.Event< TeleportMarkerBase > PlayerPre = new SteamVR_Events.Event< TeleportMarkerBase >();
  99. public static SteamVR_Events.Action< TeleportMarkerBase > PlayerPreAction( UnityAction< TeleportMarkerBase > action ) { return new SteamVR_Events.Action< TeleportMarkerBase >( PlayerPre, action ); }
  100. //-------------------------------------------------
  101. private static Teleport _instance;
  102. public static Teleport instance
  103. {
  104. get
  105. {
  106. if ( _instance == null )
  107. {
  108. _instance = GameObject.FindObjectOfType<Teleport>();
  109. }
  110. return _instance;
  111. }
  112. }
  113. //-------------------------------------------------
  114. void Awake()
  115. {
  116. _instance = this;
  117. chaperoneInfoInitializedAction = ChaperoneInfo.InitializedAction( OnChaperoneInfoInitialized );
  118. pointerLineRenderer = GetComponentInChildren<LineRenderer>();
  119. teleportPointerObject = pointerLineRenderer.gameObject;
  120. int tintColorID = Shader.PropertyToID( "_TintColor" );
  121. fullTintAlpha = pointVisibleMaterial.GetColor( tintColorID ).a;
  122. teleportArc = GetComponent<TeleportArc>();
  123. teleportArc.traceLayerMask = traceLayerMask;
  124. loopingAudioMaxVolume = loopingAudioSource.volume;
  125. playAreaPreviewCorner.SetActive( false );
  126. playAreaPreviewSide.SetActive( false );
  127. float invalidReticleStartingScale = invalidReticleTransform.localScale.x;
  128. invalidReticleMinScale *= invalidReticleStartingScale;
  129. invalidReticleMaxScale *= invalidReticleStartingScale;
  130. }
  131. //-------------------------------------------------
  132. void Start()
  133. {
  134. teleportMarkers = GameObject.FindObjectsOfType<TeleportMarkerBase>();
  135. HidePointer();
  136. player = InteractionSystem.Player.instance;
  137. if ( player == null )
  138. {
  139. Debug.LogError( "Teleport: No Player instance found in map." );
  140. Destroy( this.gameObject );
  141. return;
  142. }
  143. CheckForSpawnPoint();
  144. Invoke( "ShowTeleportHint", 5.0f );
  145. }
  146. //-------------------------------------------------
  147. void OnEnable()
  148. {
  149. chaperoneInfoInitializedAction.enabled = true;
  150. OnChaperoneInfoInitialized(); // In case it's already initialized
  151. }
  152. //-------------------------------------------------
  153. void OnDisable()
  154. {
  155. chaperoneInfoInitializedAction.enabled = false;
  156. HidePointer();
  157. }
  158. //-------------------------------------------------
  159. private void CheckForSpawnPoint()
  160. {
  161. foreach ( TeleportMarkerBase teleportMarker in teleportMarkers )
  162. {
  163. TeleportPoint teleportPoint = teleportMarker as TeleportPoint;
  164. if ( teleportPoint && teleportPoint.playerSpawnPoint )
  165. {
  166. teleportingToMarker = teleportMarker;
  167. TeleportPlayer();
  168. break;
  169. }
  170. }
  171. }
  172. //-------------------------------------------------
  173. public void HideTeleportPointer()
  174. {
  175. if ( pointerHand != null )
  176. {
  177. HidePointer();
  178. }
  179. }
  180. //-------------------------------------------------
  181. void Update()
  182. {
  183. Hand oldPointerHand = pointerHand;
  184. Hand newPointerHand = null;
  185. foreach ( Hand hand in player.hands )
  186. {
  187. if ( visible )
  188. {
  189. if ( WasTeleportButtonReleased( hand ) )
  190. {
  191. if ( pointerHand == hand ) //This is the pointer hand
  192. {
  193. TryTeleportPlayer();
  194. }
  195. }
  196. }
  197. if ( WasTeleportButtonPressed( hand ) )
  198. {
  199. newPointerHand = hand;
  200. }
  201. }
  202. //If something is attached to the hand that is preventing teleport
  203. if ( allowTeleportWhileAttached && !allowTeleportWhileAttached.teleportAllowed )
  204. {
  205. HidePointer();
  206. }
  207. else
  208. {
  209. if ( !visible && newPointerHand != null )
  210. {
  211. //Begin showing the pointer
  212. ShowPointer( newPointerHand, oldPointerHand );
  213. }
  214. else if ( visible )
  215. {
  216. if ( newPointerHand == null && !IsTeleportButtonDown( pointerHand ) )
  217. {
  218. //Hide the pointer
  219. HidePointer();
  220. }
  221. else if ( newPointerHand != null )
  222. {
  223. //Move the pointer to a new hand
  224. ShowPointer( newPointerHand, oldPointerHand );
  225. }
  226. }
  227. }
  228. if ( visible )
  229. {
  230. UpdatePointer();
  231. if ( meshFading )
  232. {
  233. UpdateTeleportColors();
  234. }
  235. if ( onActivateObjectTransform.gameObject.activeSelf && Time.time - pointerShowStartTime > activateObjectTime )
  236. {
  237. onActivateObjectTransform.gameObject.SetActive( false );
  238. }
  239. }
  240. else
  241. {
  242. if ( onDeactivateObjectTransform.gameObject.activeSelf && Time.time - pointerHideStartTime > deactivateObjectTime )
  243. {
  244. onDeactivateObjectTransform.gameObject.SetActive( false );
  245. }
  246. }
  247. }
  248. //-------------------------------------------------
  249. private void UpdatePointer()
  250. {
  251. Vector3 pointerStart = pointerStartTransform.position;
  252. Vector3 pointerEnd;
  253. Vector3 pointerDir = pointerStartTransform.forward;
  254. bool hitSomething = false;
  255. bool showPlayAreaPreview = false;
  256. Vector3 playerFeetOffset = player.trackingOriginTransform.position - player.feetPositionGuess;
  257. Vector3 arcVelocity = pointerDir * arcDistance;
  258. TeleportMarkerBase hitTeleportMarker = null;
  259. //Check pointer angle
  260. float dotUp = Vector3.Dot( pointerDir, Vector3.up );
  261. float dotForward = Vector3.Dot( pointerDir, player.hmdTransform.forward );
  262. bool pointerAtBadAngle = false;
  263. if ( ( dotForward > 0 && dotUp > 0.75f ) || ( dotForward < 0.0f && dotUp > 0.5f ) )
  264. {
  265. pointerAtBadAngle = true;
  266. }
  267. //Trace to see if the pointer hit anything
  268. RaycastHit hitInfo;
  269. teleportArc.SetArcData( pointerStart, arcVelocity, true, pointerAtBadAngle );
  270. if ( teleportArc.DrawArc( out hitInfo ) )
  271. {
  272. hitSomething = true;
  273. hitTeleportMarker = hitInfo.collider.GetComponentInParent<TeleportMarkerBase>();
  274. }
  275. if ( pointerAtBadAngle )
  276. {
  277. hitTeleportMarker = null;
  278. }
  279. HighlightSelected( hitTeleportMarker );
  280. if ( hitTeleportMarker != null ) //Hit a teleport marker
  281. {
  282. if ( hitTeleportMarker.locked )
  283. {
  284. teleportArc.SetColor( pointerLockedColor );
  285. #if (UNITY_5_4)
  286. pointerLineRenderer.SetColors( pointerLockedColor, pointerLockedColor );
  287. #else
  288. pointerLineRenderer.startColor = pointerLockedColor;
  289. pointerLineRenderer.endColor = pointerLockedColor;
  290. #endif
  291. destinationReticleTransform.gameObject.SetActive( false );
  292. }
  293. else
  294. {
  295. teleportArc.SetColor( pointerValidColor );
  296. #if (UNITY_5_4)
  297. pointerLineRenderer.SetColors( pointerValidColor, pointerValidColor );
  298. #else
  299. pointerLineRenderer.startColor = pointerValidColor;
  300. pointerLineRenderer.endColor = pointerValidColor;
  301. #endif
  302. destinationReticleTransform.gameObject.SetActive( hitTeleportMarker.showReticle );
  303. }
  304. offsetReticleTransform.gameObject.SetActive( true );
  305. invalidReticleTransform.gameObject.SetActive( false );
  306. pointedAtTeleportMarker = hitTeleportMarker;
  307. pointedAtPosition = hitInfo.point;
  308. if ( showPlayAreaMarker )
  309. {
  310. //Show the play area marker if this is a teleport area
  311. TeleportArea teleportArea = pointedAtTeleportMarker as TeleportArea;
  312. if ( teleportArea != null && !teleportArea.locked && playAreaPreviewTransform != null )
  313. {
  314. Vector3 offsetToUse = playerFeetOffset;
  315. //Adjust the actual offset to prevent the play area marker from moving too much
  316. if ( !movedFeetFarEnough )
  317. {
  318. float distanceFromStartingOffset = Vector3.Distance( playerFeetOffset, startingFeetOffset );
  319. if ( distanceFromStartingOffset < 0.1f )
  320. {
  321. offsetToUse = startingFeetOffset;
  322. }
  323. else if ( distanceFromStartingOffset < 0.4f )
  324. {
  325. offsetToUse = Vector3.Lerp( startingFeetOffset, playerFeetOffset, ( distanceFromStartingOffset - 0.1f ) / 0.3f );
  326. }
  327. else
  328. {
  329. movedFeetFarEnough = true;
  330. }
  331. }
  332. playAreaPreviewTransform.position = pointedAtPosition + offsetToUse;
  333. showPlayAreaPreview = true;
  334. }
  335. }
  336. pointerEnd = hitInfo.point;
  337. }
  338. else //Hit neither
  339. {
  340. destinationReticleTransform.gameObject.SetActive( false );
  341. offsetReticleTransform.gameObject.SetActive( false );
  342. teleportArc.SetColor( pointerInvalidColor );
  343. #if (UNITY_5_4)
  344. pointerLineRenderer.SetColors( pointerInvalidColor, pointerInvalidColor );
  345. #else
  346. pointerLineRenderer.startColor = pointerInvalidColor;
  347. pointerLineRenderer.endColor = pointerInvalidColor;
  348. #endif
  349. invalidReticleTransform.gameObject.SetActive( !pointerAtBadAngle );
  350. //Orient the invalid reticle to the normal of the trace hit point
  351. Vector3 normalToUse = hitInfo.normal;
  352. float angle = Vector3.Angle( hitInfo.normal, Vector3.up );
  353. if ( angle < 15.0f )
  354. {
  355. normalToUse = Vector3.up;
  356. }
  357. invalidReticleTargetRotation = Quaternion.FromToRotation( Vector3.up, normalToUse );
  358. invalidReticleTransform.rotation = Quaternion.Slerp( invalidReticleTransform.rotation, invalidReticleTargetRotation, 0.1f );
  359. //Scale the invalid reticle based on the distance from the player
  360. float distanceFromPlayer = Vector3.Distance( hitInfo.point, player.hmdTransform.position );
  361. float invalidReticleCurrentScale = Util.RemapNumberClamped( distanceFromPlayer, invalidReticleMinScaleDistance, invalidReticleMaxScaleDistance, invalidReticleMinScale, invalidReticleMaxScale );
  362. invalidReticleScale.x = invalidReticleCurrentScale;
  363. invalidReticleScale.y = invalidReticleCurrentScale;
  364. invalidReticleScale.z = invalidReticleCurrentScale;
  365. invalidReticleTransform.transform.localScale = invalidReticleScale;
  366. pointedAtTeleportMarker = null;
  367. if ( hitSomething )
  368. {
  369. pointerEnd = hitInfo.point;
  370. }
  371. else
  372. {
  373. pointerEnd = teleportArc.GetArcPositionAtTime( teleportArc.arcDuration );
  374. }
  375. //Debug floor
  376. if ( debugFloor )
  377. {
  378. floorDebugSphere.gameObject.SetActive( false );
  379. floorDebugLine.gameObject.SetActive( false );
  380. }
  381. }
  382. if ( playAreaPreviewTransform != null )
  383. {
  384. playAreaPreviewTransform.gameObject.SetActive( showPlayAreaPreview );
  385. }
  386. if ( !showOffsetReticle )
  387. {
  388. offsetReticleTransform.gameObject.SetActive( false );
  389. }
  390. destinationReticleTransform.position = pointedAtPosition;
  391. invalidReticleTransform.position = pointerEnd;
  392. onActivateObjectTransform.position = pointerEnd;
  393. onDeactivateObjectTransform.position = pointerEnd;
  394. offsetReticleTransform.position = pointerEnd - playerFeetOffset;
  395. reticleAudioSource.transform.position = pointedAtPosition;
  396. pointerLineRenderer.SetPosition( 0, pointerStart );
  397. pointerLineRenderer.SetPosition( 1, pointerEnd );
  398. }
  399. //-------------------------------------------------
  400. void FixedUpdate()
  401. {
  402. if ( !visible )
  403. {
  404. return;
  405. }
  406. if ( debugFloor )
  407. {
  408. //Debug floor
  409. TeleportArea teleportArea = pointedAtTeleportMarker as TeleportArea;
  410. if ( teleportArea != null )
  411. {
  412. if ( floorFixupMaximumTraceDistance > 0.0f )
  413. {
  414. floorDebugSphere.gameObject.SetActive( true );
  415. floorDebugLine.gameObject.SetActive( true );
  416. RaycastHit raycastHit;
  417. Vector3 traceDir = Vector3.down;
  418. traceDir.x = 0.01f;
  419. if ( Physics.Raycast( pointedAtPosition + 0.05f * traceDir, traceDir, out raycastHit, floorFixupMaximumTraceDistance, floorFixupTraceLayerMask ) )
  420. {
  421. floorDebugSphere.transform.position = raycastHit.point;
  422. floorDebugSphere.material.color = Color.green;
  423. #if (UNITY_5_4)
  424. floorDebugLine.SetColors( Color.green, Color.green );
  425. #else
  426. floorDebugLine.startColor = Color.green;
  427. floorDebugLine.endColor = Color.green;
  428. #endif
  429. floorDebugLine.SetPosition( 0, pointedAtPosition );
  430. floorDebugLine.SetPosition( 1, raycastHit.point );
  431. }
  432. else
  433. {
  434. Vector3 rayEnd = pointedAtPosition + ( traceDir * floorFixupMaximumTraceDistance );
  435. floorDebugSphere.transform.position = rayEnd;
  436. floorDebugSphere.material.color = Color.red;
  437. #if (UNITY_5_4)
  438. floorDebugLine.SetColors( Color.red, Color.red );
  439. #else
  440. floorDebugLine.startColor = Color.red;
  441. floorDebugLine.endColor = Color.red;
  442. #endif
  443. floorDebugLine.SetPosition( 0, pointedAtPosition );
  444. floorDebugLine.SetPosition( 1, rayEnd );
  445. }
  446. }
  447. }
  448. }
  449. }
  450. //-------------------------------------------------
  451. private void OnChaperoneInfoInitialized()
  452. {
  453. ChaperoneInfo chaperone = ChaperoneInfo.instance;
  454. if ( chaperone.initialized && chaperone.roomscale )
  455. {
  456. //Set up the render model for the play area bounds
  457. if ( playAreaPreviewTransform == null )
  458. {
  459. playAreaPreviewTransform = new GameObject( "PlayAreaPreviewTransform" ).transform;
  460. playAreaPreviewTransform.parent = transform;
  461. Util.ResetTransform( playAreaPreviewTransform );
  462. playAreaPreviewCorner.SetActive( true );
  463. playAreaPreviewCorners = new Transform[4];
  464. playAreaPreviewCorners[0] = playAreaPreviewCorner.transform;
  465. playAreaPreviewCorners[1] = Instantiate( playAreaPreviewCorners[0] );
  466. playAreaPreviewCorners[2] = Instantiate( playAreaPreviewCorners[0] );
  467. playAreaPreviewCorners[3] = Instantiate( playAreaPreviewCorners[0] );
  468. playAreaPreviewCorners[0].transform.parent = playAreaPreviewTransform;
  469. playAreaPreviewCorners[1].transform.parent = playAreaPreviewTransform;
  470. playAreaPreviewCorners[2].transform.parent = playAreaPreviewTransform;
  471. playAreaPreviewCorners[3].transform.parent = playAreaPreviewTransform;
  472. playAreaPreviewSide.SetActive( true );
  473. playAreaPreviewSides = new Transform[4];
  474. playAreaPreviewSides[0] = playAreaPreviewSide.transform;
  475. playAreaPreviewSides[1] = Instantiate( playAreaPreviewSides[0] );
  476. playAreaPreviewSides[2] = Instantiate( playAreaPreviewSides[0] );
  477. playAreaPreviewSides[3] = Instantiate( playAreaPreviewSides[0] );
  478. playAreaPreviewSides[0].transform.parent = playAreaPreviewTransform;
  479. playAreaPreviewSides[1].transform.parent = playAreaPreviewTransform;
  480. playAreaPreviewSides[2].transform.parent = playAreaPreviewTransform;
  481. playAreaPreviewSides[3].transform.parent = playAreaPreviewTransform;
  482. }
  483. float x = chaperone.playAreaSizeX;
  484. float z = chaperone.playAreaSizeZ;
  485. playAreaPreviewSides[0].localPosition = new Vector3( 0.0f, 0.0f, 0.5f * z - 0.25f );
  486. playAreaPreviewSides[1].localPosition = new Vector3( 0.0f, 0.0f, -0.5f * z + 0.25f );
  487. playAreaPreviewSides[2].localPosition = new Vector3( 0.5f * x - 0.25f, 0.0f, 0.0f );
  488. playAreaPreviewSides[3].localPosition = new Vector3( -0.5f * x + 0.25f, 0.0f, 0.0f );
  489. playAreaPreviewSides[0].localScale = new Vector3( x - 0.5f, 1.0f, 1.0f );
  490. playAreaPreviewSides[1].localScale = new Vector3( x - 0.5f, 1.0f, 1.0f );
  491. playAreaPreviewSides[2].localScale = new Vector3( z - 0.5f, 1.0f, 1.0f );
  492. playAreaPreviewSides[3].localScale = new Vector3( z - 0.5f, 1.0f, 1.0f );
  493. playAreaPreviewSides[0].localRotation = Quaternion.Euler( 0.0f, 0.0f, 0.0f );
  494. playAreaPreviewSides[1].localRotation = Quaternion.Euler( 0.0f, 180.0f, 0.0f );
  495. playAreaPreviewSides[2].localRotation = Quaternion.Euler( 0.0f, 90.0f, 0.0f );
  496. playAreaPreviewSides[3].localRotation = Quaternion.Euler( 0.0f, 270.0f, 0.0f );
  497. playAreaPreviewCorners[0].localPosition = new Vector3( 0.5f * x - 0.25f, 0.0f, 0.5f * z - 0.25f );
  498. playAreaPreviewCorners[1].localPosition = new Vector3( 0.5f * x - 0.25f, 0.0f, -0.5f * z + 0.25f );
  499. playAreaPreviewCorners[2].localPosition = new Vector3( -0.5f * x + 0.25f, 0.0f, -0.5f * z + 0.25f );
  500. playAreaPreviewCorners[3].localPosition = new Vector3( -0.5f * x + 0.25f, 0.0f, 0.5f * z - 0.25f );
  501. playAreaPreviewCorners[0].localRotation = Quaternion.Euler( 0.0f, 0.0f, 0.0f );
  502. playAreaPreviewCorners[1].localRotation = Quaternion.Euler( 0.0f, 90.0f, 0.0f );
  503. playAreaPreviewCorners[2].localRotation = Quaternion.Euler( 0.0f, 180.0f, 0.0f );
  504. playAreaPreviewCorners[3].localRotation = Quaternion.Euler( 0.0f, 270.0f, 0.0f );
  505. playAreaPreviewTransform.gameObject.SetActive( false );
  506. }
  507. }
  508. //-------------------------------------------------
  509. private void HidePointer()
  510. {
  511. if ( visible )
  512. {
  513. pointerHideStartTime = Time.time;
  514. }
  515. visible = false;
  516. if ( pointerHand )
  517. {
  518. if ( ShouldOverrideHoverLock() )
  519. {
  520. //Restore the original hovering interactable on the hand
  521. if ( originalHoverLockState == true )
  522. {
  523. pointerHand.HoverLock( originalHoveringInteractable );
  524. }
  525. else
  526. {
  527. pointerHand.HoverUnlock( null );
  528. }
  529. }
  530. //Stop looping sound
  531. loopingAudioSource.Stop();
  532. PlayAudioClip( pointerAudioSource, pointerStopSound );
  533. }
  534. teleportPointerObject.SetActive( false );
  535. teleportArc.Hide();
  536. foreach ( TeleportMarkerBase teleportMarker in teleportMarkers )
  537. {
  538. if ( teleportMarker != null && teleportMarker.markerActive && teleportMarker.gameObject != null )
  539. {
  540. teleportMarker.gameObject.SetActive( false );
  541. }
  542. }
  543. destinationReticleTransform.gameObject.SetActive( false );
  544. invalidReticleTransform.gameObject.SetActive( false );
  545. offsetReticleTransform.gameObject.SetActive( false );
  546. if ( playAreaPreviewTransform != null )
  547. {
  548. playAreaPreviewTransform.gameObject.SetActive( false );
  549. }
  550. if ( onActivateObjectTransform.gameObject.activeSelf )
  551. {
  552. onActivateObjectTransform.gameObject.SetActive( false );
  553. }
  554. onDeactivateObjectTransform.gameObject.SetActive( true );
  555. pointerHand = null;
  556. }
  557. //-------------------------------------------------
  558. private void ShowPointer( Hand newPointerHand, Hand oldPointerHand )
  559. {
  560. if ( !visible )
  561. {
  562. pointedAtTeleportMarker = null;
  563. pointerShowStartTime = Time.time;
  564. visible = true;
  565. meshFading = true;
  566. teleportPointerObject.SetActive( false );
  567. teleportArc.Show();
  568. foreach ( TeleportMarkerBase teleportMarker in teleportMarkers )
  569. {
  570. if ( teleportMarker.markerActive && teleportMarker.ShouldActivate( player.feetPositionGuess ) )
  571. {
  572. teleportMarker.gameObject.SetActive( true );
  573. teleportMarker.Highlight( false );
  574. }
  575. }
  576. startingFeetOffset = player.trackingOriginTransform.position - player.feetPositionGuess;
  577. movedFeetFarEnough = false;
  578. if ( onDeactivateObjectTransform.gameObject.activeSelf )
  579. {
  580. onDeactivateObjectTransform.gameObject.SetActive( false );
  581. }
  582. onActivateObjectTransform.gameObject.SetActive( true );
  583. loopingAudioSource.clip = pointerLoopSound;
  584. loopingAudioSource.loop = true;
  585. loopingAudioSource.Play();
  586. loopingAudioSource.volume = 0.0f;
  587. }
  588. if ( oldPointerHand )
  589. {
  590. if ( ShouldOverrideHoverLock() )
  591. {
  592. //Restore the original hovering interactable on the hand
  593. if ( originalHoverLockState == true )
  594. {
  595. oldPointerHand.HoverLock( originalHoveringInteractable );
  596. }
  597. else
  598. {
  599. oldPointerHand.HoverUnlock( null );
  600. }
  601. }
  602. }
  603. pointerHand = newPointerHand;
  604. if ( visible && oldPointerHand != pointerHand )
  605. {
  606. PlayAudioClip( pointerAudioSource, pointerStartSound );
  607. }
  608. if ( pointerHand )
  609. {
  610. pointerStartTransform = GetPointerStartTransform( pointerHand );
  611. if ( pointerHand.currentAttachedObject != null )
  612. {
  613. allowTeleportWhileAttached = pointerHand.currentAttachedObject.GetComponent<AllowTeleportWhileAttachedToHand>();
  614. }
  615. //Keep track of any existing hovering interactable on the hand
  616. originalHoverLockState = pointerHand.hoverLocked;
  617. originalHoveringInteractable = pointerHand.hoveringInteractable;
  618. if ( ShouldOverrideHoverLock() )
  619. {
  620. pointerHand.HoverLock( null );
  621. }
  622. pointerAudioSource.transform.SetParent( pointerStartTransform );
  623. pointerAudioSource.transform.localPosition = Vector3.zero;
  624. loopingAudioSource.transform.SetParent( pointerStartTransform );
  625. loopingAudioSource.transform.localPosition = Vector3.zero;
  626. }
  627. }
  628. //-------------------------------------------------
  629. private void UpdateTeleportColors()
  630. {
  631. float deltaTime = Time.time - pointerShowStartTime;
  632. if ( deltaTime > meshFadeTime )
  633. {
  634. meshAlphaPercent = 1.0f;
  635. meshFading = false;
  636. }
  637. else
  638. {
  639. meshAlphaPercent = Mathf.Lerp( 0.0f, 1.0f, deltaTime / meshFadeTime );
  640. }
  641. //Tint color for the teleport points
  642. foreach ( TeleportMarkerBase teleportMarker in teleportMarkers )
  643. {
  644. teleportMarker.SetAlpha( fullTintAlpha * meshAlphaPercent, meshAlphaPercent );
  645. }
  646. }
  647. //-------------------------------------------------
  648. private void PlayAudioClip( AudioSource source, AudioClip clip )
  649. {
  650. source.clip = clip;
  651. source.Play();
  652. }
  653. //-------------------------------------------------
  654. private void PlayPointerHaptic( bool validLocation )
  655. {
  656. if ( pointerHand.controller != null )
  657. {
  658. if ( validLocation )
  659. {
  660. pointerHand.controller.TriggerHapticPulse( 800 );
  661. }
  662. else
  663. {
  664. pointerHand.controller.TriggerHapticPulse( 100 );
  665. }
  666. }
  667. }
  668. //-------------------------------------------------
  669. private void TryTeleportPlayer()
  670. {
  671. if ( visible && !teleporting )
  672. {
  673. if ( pointedAtTeleportMarker != null && pointedAtTeleportMarker.locked == false )
  674. {
  675. //Pointing at an unlocked teleport marker
  676. teleportingToMarker = pointedAtTeleportMarker;
  677. InitiateTeleportFade();
  678. CancelTeleportHint();
  679. }
  680. }
  681. }
  682. //-------------------------------------------------
  683. private void InitiateTeleportFade()
  684. {
  685. teleporting = true;
  686. currentFadeTime = teleportFadeTime;
  687. TeleportPoint teleportPoint = teleportingToMarker as TeleportPoint;
  688. if ( teleportPoint != null && teleportPoint.teleportType == TeleportPoint.TeleportPointType.SwitchToNewScene )
  689. {
  690. currentFadeTime *= 3.0f;
  691. Teleport.ChangeScene.Send( currentFadeTime );
  692. }
  693. SteamVR_Fade.Start( Color.clear, 0 );
  694. SteamVR_Fade.Start( Color.black, currentFadeTime );
  695. headAudioSource.transform.SetParent( player.hmdTransform );
  696. headAudioSource.transform.localPosition = Vector3.zero;
  697. PlayAudioClip( headAudioSource, teleportSound );
  698. Invoke( "TeleportPlayer", currentFadeTime );
  699. }
  700. //-------------------------------------------------
  701. private void TeleportPlayer()
  702. {
  703. teleporting = false;
  704. Teleport.PlayerPre.Send( pointedAtTeleportMarker );
  705. SteamVR_Fade.Start( Color.clear, currentFadeTime );
  706. TeleportPoint teleportPoint = teleportingToMarker as TeleportPoint;
  707. Vector3 teleportPosition = pointedAtPosition;
  708. if ( teleportPoint != null )
  709. {
  710. teleportPosition = teleportPoint.transform.position;
  711. //Teleport to a new scene
  712. if ( teleportPoint.teleportType == TeleportPoint.TeleportPointType.SwitchToNewScene )
  713. {
  714. teleportPoint.TeleportToScene();
  715. return;
  716. }
  717. }
  718. // Find the actual floor position below the navigation mesh
  719. TeleportArea teleportArea = teleportingToMarker as TeleportArea;
  720. if ( teleportArea != null )
  721. {
  722. if ( floorFixupMaximumTraceDistance > 0.0f )
  723. {
  724. RaycastHit raycastHit;
  725. if ( Physics.Raycast( teleportPosition + 0.05f * Vector3.down, Vector3.down, out raycastHit, floorFixupMaximumTraceDistance, floorFixupTraceLayerMask ) )
  726. {
  727. teleportPosition = raycastHit.point;
  728. }
  729. }
  730. }
  731. if ( teleportingToMarker.ShouldMovePlayer() )
  732. {
  733. Vector3 playerFeetOffset = player.trackingOriginTransform.position - player.feetPositionGuess;
  734. player.trackingOriginTransform.position = teleportPosition + playerFeetOffset;
  735. }
  736. else
  737. {
  738. teleportingToMarker.TeleportPlayer( pointedAtPosition );
  739. }
  740. Teleport.Player.Send( pointedAtTeleportMarker );
  741. }
  742. //-------------------------------------------------
  743. private void HighlightSelected( TeleportMarkerBase hitTeleportMarker )
  744. {
  745. if ( pointedAtTeleportMarker != hitTeleportMarker ) //Pointing at a new teleport marker
  746. {
  747. if ( pointedAtTeleportMarker != null )
  748. {
  749. pointedAtTeleportMarker.Highlight( false );
  750. }
  751. if ( hitTeleportMarker != null )
  752. {
  753. hitTeleportMarker.Highlight( true );
  754. prevPointedAtPosition = pointedAtPosition;
  755. PlayPointerHaptic( !hitTeleportMarker.locked );
  756. PlayAudioClip( reticleAudioSource, goodHighlightSound );
  757. loopingAudioSource.volume = loopingAudioMaxVolume;
  758. }
  759. else if ( pointedAtTeleportMarker != null )
  760. {
  761. PlayAudioClip( reticleAudioSource, badHighlightSound );
  762. loopingAudioSource.volume = 0.0f;
  763. }
  764. }
  765. else if ( hitTeleportMarker != null ) //Pointing at the same teleport marker
  766. {
  767. if ( Vector3.Distance( prevPointedAtPosition, pointedAtPosition ) > 1.0f )
  768. {
  769. prevPointedAtPosition = pointedAtPosition;
  770. PlayPointerHaptic( !hitTeleportMarker.locked );
  771. }
  772. }
  773. }
  774. //-------------------------------------------------
  775. public void ShowTeleportHint()
  776. {
  777. CancelTeleportHint();
  778. hintCoroutine = StartCoroutine( TeleportHintCoroutine() );
  779. }
  780. //-------------------------------------------------
  781. public void CancelTeleportHint()
  782. {
  783. if ( hintCoroutine != null )
  784. {
  785. foreach ( Hand hand in player.hands )
  786. {
  787. ControllerButtonHints.HideTextHint( hand, EVRButtonId.k_EButton_SteamVR_Touchpad );
  788. }
  789. StopCoroutine( hintCoroutine );
  790. hintCoroutine = null;
  791. }
  792. CancelInvoke( "ShowTeleportHint" );
  793. }
  794. //-------------------------------------------------
  795. private IEnumerator TeleportHintCoroutine()
  796. {
  797. float prevBreakTime = Time.time;
  798. float prevHapticPulseTime = Time.time;
  799. while ( true )
  800. {
  801. bool pulsed = false;
  802. //Show the hint on each eligible hand
  803. foreach ( Hand hand in player.hands )
  804. {
  805. bool showHint = IsEligibleForTeleport( hand );
  806. bool isShowingHint = !string.IsNullOrEmpty( ControllerButtonHints.GetActiveHintText( hand, EVRButtonId.k_EButton_SteamVR_Touchpad ) );
  807. if ( showHint )
  808. {
  809. if ( !isShowingHint )
  810. {
  811. ControllerButtonHints.ShowTextHint( hand, EVRButtonId.k_EButton_SteamVR_Touchpad, "Teleport" );
  812. prevBreakTime = Time.time;
  813. prevHapticPulseTime = Time.time;
  814. }
  815. if ( Time.time > prevHapticPulseTime + 0.05f )
  816. {
  817. //Haptic pulse for a few seconds
  818. pulsed = true;
  819. hand.controller.TriggerHapticPulse( 500 );
  820. }
  821. }
  822. else if ( !showHint && isShowingHint )
  823. {
  824. ControllerButtonHints.HideTextHint( hand, EVRButtonId.k_EButton_SteamVR_Touchpad );
  825. }
  826. }
  827. if ( Time.time > prevBreakTime + 3.0f )
  828. {
  829. //Take a break for a few seconds
  830. yield return new WaitForSeconds( 3.0f );
  831. prevBreakTime = Time.time;
  832. }
  833. if ( pulsed )
  834. {
  835. prevHapticPulseTime = Time.time;
  836. }
  837. yield return null;
  838. }
  839. }
  840. //-------------------------------------------------
  841. public bool IsEligibleForTeleport( Hand hand )
  842. {
  843. if ( hand == null )
  844. {
  845. return false;
  846. }
  847. if ( !hand.gameObject.activeInHierarchy )
  848. {
  849. return false;
  850. }
  851. if ( hand.hoveringInteractable != null )
  852. {
  853. return false;
  854. }
  855. if ( hand.noSteamVRFallbackCamera == null )
  856. {
  857. if ( hand.controller == null )
  858. {
  859. return false;
  860. }
  861. //Something is attached to the hand
  862. if ( hand.currentAttachedObject != null )
  863. {
  864. AllowTeleportWhileAttachedToHand allowTeleportWhileAttachedToHand = hand.currentAttachedObject.GetComponent<AllowTeleportWhileAttachedToHand>();
  865. if ( allowTeleportWhileAttachedToHand != null && allowTeleportWhileAttachedToHand.teleportAllowed == true )
  866. {
  867. return true;
  868. }
  869. else
  870. {
  871. return false;
  872. }
  873. }
  874. }
  875. return true;
  876. }
  877. //-------------------------------------------------
  878. private bool ShouldOverrideHoverLock()
  879. {
  880. if ( !allowTeleportWhileAttached || allowTeleportWhileAttached.overrideHoverLock )
  881. {
  882. return true;
  883. }
  884. return false;
  885. }
  886. //-------------------------------------------------
  887. private bool WasTeleportButtonReleased( Hand hand )
  888. {
  889. if ( IsEligibleForTeleport( hand ) )
  890. {
  891. if ( hand.noSteamVRFallbackCamera != null )
  892. {
  893. return Input.GetKeyUp( KeyCode.T );
  894. }
  895. else
  896. {
  897. return hand.controller.GetPressUp( SteamVR_Controller.ButtonMask.Touchpad );
  898. }
  899. }
  900. return false;
  901. }
  902. //-------------------------------------------------
  903. private bool IsTeleportButtonDown( Hand hand )
  904. {
  905. if ( IsEligibleForTeleport( hand ) )
  906. {
  907. if ( hand.noSteamVRFallbackCamera != null )
  908. {
  909. return Input.GetKey( KeyCode.T );
  910. }
  911. else
  912. {
  913. return hand.controller.GetPress( SteamVR_Controller.ButtonMask.Touchpad );
  914. }
  915. }
  916. return false;
  917. }
  918. //-------------------------------------------------
  919. private bool WasTeleportButtonPressed( Hand hand )
  920. {
  921. if ( IsEligibleForTeleport( hand ) )
  922. {
  923. if ( hand.noSteamVRFallbackCamera != null )
  924. {
  925. return Input.GetKeyDown( KeyCode.T );
  926. }
  927. else
  928. {
  929. return hand.controller.GetPressDown( SteamVR_Controller.ButtonMask.Touchpad );
  930. }
  931. }
  932. return false;
  933. }
  934. //-------------------------------------------------
  935. private Transform GetPointerStartTransform( Hand hand )
  936. {
  937. if ( hand.noSteamVRFallbackCamera != null )
  938. {
  939. return hand.noSteamVRFallbackCamera.transform;
  940. }
  941. else
  942. {
  943. return pointerHand.GetAttachmentTransform( "Attach_ControllerTip" );
  944. }
  945. }
  946. }
  947. }