Teleport.cs 33 KB

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