Teleport.cs 33 KB

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