//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
|
//
|
|
// Purpose: Handles all the teleport logic
|
|
//
|
|
//=============================================================================
|
|
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using System.Collections;
|
|
|
|
namespace Valve.VR.InteractionSystem
|
|
{
|
|
//-------------------------------------------------------------------------
|
|
public class Teleport : MonoBehaviour
|
|
{
|
|
public LayerMask traceLayerMask;
|
|
public LayerMask floorFixupTraceLayerMask;
|
|
public float floorFixupMaximumTraceDistance = 1.0f;
|
|
public Material areaVisibleMaterial;
|
|
public Material areaLockedMaterial;
|
|
public Material areaHighlightedMaterial;
|
|
public Material pointVisibleMaterial;
|
|
public Material pointLockedMaterial;
|
|
public Material pointHighlightedMaterial;
|
|
public Transform destinationReticleTransform;
|
|
public Transform invalidReticleTransform;
|
|
public GameObject playAreaPreviewCorner;
|
|
public GameObject playAreaPreviewSide;
|
|
public Color pointerValidColor;
|
|
public Color pointerInvalidColor;
|
|
public Color pointerLockedColor;
|
|
public bool showPlayAreaMarker = true;
|
|
|
|
public float teleportFadeTime = 0.1f;
|
|
public float meshFadeTime = 0.2f;
|
|
|
|
public float arcDistance = 10.0f;
|
|
|
|
[Header( "Effects" )]
|
|
public Transform onActivateObjectTransform;
|
|
public Transform onDeactivateObjectTransform;
|
|
public float activateObjectTime = 1.0f;
|
|
public float deactivateObjectTime = 1.0f;
|
|
|
|
[Header( "Audio Sources" )]
|
|
public AudioSource pointerAudioSource;
|
|
public AudioSource loopingAudioSource;
|
|
public AudioSource headAudioSource;
|
|
public AudioSource reticleAudioSource;
|
|
|
|
[Header( "Sounds" )]
|
|
public AudioClip teleportSound;
|
|
public AudioClip pointerStartSound;
|
|
public AudioClip pointerLoopSound;
|
|
public AudioClip pointerStopSound;
|
|
public AudioClip goodHighlightSound;
|
|
public AudioClip badHighlightSound;
|
|
|
|
[Header( "Debug" )]
|
|
public bool debugFloor = false;
|
|
public bool showOffsetReticle = false;
|
|
public Transform offsetReticleTransform;
|
|
public MeshRenderer floorDebugSphere;
|
|
public LineRenderer floorDebugLine;
|
|
|
|
private LineRenderer pointerLineRenderer;
|
|
private GameObject teleportPointerObject;
|
|
private Transform pointerStartTransform;
|
|
private Hand pointerHand = null;
|
|
private Player player = null;
|
|
private TeleportArc teleportArc = null;
|
|
|
|
private bool visible = false;
|
|
|
|
private TeleportMarkerBase[] teleportMarkers;
|
|
private TeleportMarkerBase pointedAtTeleportMarker;
|
|
private TeleportMarkerBase teleportingToMarker;
|
|
private Vector3 pointedAtPosition;
|
|
private Vector3 prevPointedAtPosition;
|
|
private bool teleporting = false;
|
|
private float currentFadeTime = 0.0f;
|
|
|
|
private float meshAlphaPercent = 1.0f;
|
|
private float pointerShowStartTime = 0.0f;
|
|
private float pointerHideStartTime = 0.0f;
|
|
private bool meshFading = false;
|
|
private float fullTintAlpha;
|
|
|
|
private float invalidReticleMinScale = 0.2f;
|
|
private float invalidReticleMaxScale = 1.0f;
|
|
private float invalidReticleMinScaleDistance = 0.4f;
|
|
private float invalidReticleMaxScaleDistance = 2.0f;
|
|
private Vector3 invalidReticleScale = Vector3.one;
|
|
private Quaternion invalidReticleTargetRotation = Quaternion.identity;
|
|
|
|
private Transform playAreaPreviewTransform;
|
|
private Transform[] playAreaPreviewCorners;
|
|
private Transform[] playAreaPreviewSides;
|
|
|
|
private float loopingAudioMaxVolume = 0.0f;
|
|
|
|
private Coroutine hintCoroutine = null;
|
|
|
|
private bool originalHoverLockState = false;
|
|
private Interactable originalHoveringInteractable = null;
|
|
private AllowTeleportWhileAttachedToHand allowTeleportWhileAttached = null;
|
|
|
|
private Vector3 startingFeetOffset = Vector3.zero;
|
|
private bool movedFeetFarEnough = false;
|
|
|
|
SteamVR_Events.Action chaperoneInfoInitializedAction;
|
|
|
|
// Events
|
|
|
|
public static SteamVR_Events.Event< float > ChangeScene = new SteamVR_Events.Event< float >();
|
|
public static SteamVR_Events.Action< float > ChangeSceneAction( UnityAction< float > action ) { return new SteamVR_Events.Action< float >( ChangeScene, action ); }
|
|
|
|
public static SteamVR_Events.Event< TeleportMarkerBase > Player = new SteamVR_Events.Event< TeleportMarkerBase >();
|
|
public static SteamVR_Events.Action< TeleportMarkerBase > PlayerAction( UnityAction< TeleportMarkerBase > action ) { return new SteamVR_Events.Action< TeleportMarkerBase >( Player, action ); }
|
|
|
|
public static SteamVR_Events.Event< TeleportMarkerBase > PlayerPre = new SteamVR_Events.Event< TeleportMarkerBase >();
|
|
public static SteamVR_Events.Action< TeleportMarkerBase > PlayerPreAction( UnityAction< TeleportMarkerBase > action ) { return new SteamVR_Events.Action< TeleportMarkerBase >( PlayerPre, action ); }
|
|
|
|
//-------------------------------------------------
|
|
private static Teleport _instance;
|
|
public static Teleport instance
|
|
{
|
|
get
|
|
{
|
|
if ( _instance == null )
|
|
{
|
|
_instance = GameObject.FindObjectOfType<Teleport>();
|
|
}
|
|
|
|
return _instance;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
void Awake()
|
|
{
|
|
_instance = this;
|
|
|
|
chaperoneInfoInitializedAction = ChaperoneInfo.InitializedAction( OnChaperoneInfoInitialized );
|
|
|
|
pointerLineRenderer = GetComponentInChildren<LineRenderer>();
|
|
teleportPointerObject = pointerLineRenderer.gameObject;
|
|
|
|
int tintColorID = Shader.PropertyToID( "_TintColor" );
|
|
fullTintAlpha = pointVisibleMaterial.GetColor( tintColorID ).a;
|
|
|
|
teleportArc = GetComponent<TeleportArc>();
|
|
teleportArc.traceLayerMask = traceLayerMask;
|
|
|
|
loopingAudioMaxVolume = loopingAudioSource.volume;
|
|
|
|
playAreaPreviewCorner.SetActive( false );
|
|
playAreaPreviewSide.SetActive( false );
|
|
|
|
float invalidReticleStartingScale = invalidReticleTransform.localScale.x;
|
|
invalidReticleMinScale *= invalidReticleStartingScale;
|
|
invalidReticleMaxScale *= invalidReticleStartingScale;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
void Start()
|
|
{
|
|
teleportMarkers = GameObject.FindObjectsOfType<TeleportMarkerBase>();
|
|
|
|
HidePointer();
|
|
|
|
player = InteractionSystem.Player.instance;
|
|
|
|
if ( player == null )
|
|
{
|
|
Debug.LogError( "Teleport: No Player instance found in map." );
|
|
Destroy( this.gameObject );
|
|
return;
|
|
}
|
|
|
|
CheckForSpawnPoint();
|
|
|
|
Invoke( "ShowTeleportHint", 5.0f );
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
void OnEnable()
|
|
{
|
|
chaperoneInfoInitializedAction.enabled = true;
|
|
OnChaperoneInfoInitialized(); // In case it's already initialized
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
void OnDisable()
|
|
{
|
|
chaperoneInfoInitializedAction.enabled = false;
|
|
HidePointer();
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private void CheckForSpawnPoint()
|
|
{
|
|
foreach ( TeleportMarkerBase teleportMarker in teleportMarkers )
|
|
{
|
|
TeleportPoint teleportPoint = teleportMarker as TeleportPoint;
|
|
if ( teleportPoint && teleportPoint.playerSpawnPoint )
|
|
{
|
|
teleportingToMarker = teleportMarker;
|
|
TeleportPlayer();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
public void HideTeleportPointer()
|
|
{
|
|
if ( pointerHand != null )
|
|
{
|
|
HidePointer();
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
void Update()
|
|
{
|
|
Hand oldPointerHand = pointerHand;
|
|
Hand newPointerHand = null;
|
|
|
|
foreach ( Hand hand in player.hands )
|
|
{
|
|
if ( visible )
|
|
{
|
|
if ( WasTeleportButtonReleased( hand ) )
|
|
{
|
|
if ( pointerHand == hand ) //This is the pointer hand
|
|
{
|
|
TryTeleportPlayer();
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( WasTeleportButtonPressed( hand ) )
|
|
{
|
|
newPointerHand = hand;
|
|
}
|
|
}
|
|
|
|
//If something is attached to the hand that is preventing teleport
|
|
if ( allowTeleportWhileAttached && !allowTeleportWhileAttached.teleportAllowed )
|
|
{
|
|
HidePointer();
|
|
}
|
|
else
|
|
{
|
|
if ( !visible && newPointerHand != null )
|
|
{
|
|
//Begin showing the pointer
|
|
ShowPointer( newPointerHand, oldPointerHand );
|
|
}
|
|
else if ( visible )
|
|
{
|
|
if ( newPointerHand == null && !IsTeleportButtonDown( pointerHand ) )
|
|
{
|
|
//Hide the pointer
|
|
HidePointer();
|
|
}
|
|
else if ( newPointerHand != null )
|
|
{
|
|
//Move the pointer to a new hand
|
|
ShowPointer( newPointerHand, oldPointerHand );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( visible )
|
|
{
|
|
UpdatePointer();
|
|
|
|
if ( meshFading )
|
|
{
|
|
UpdateTeleportColors();
|
|
}
|
|
|
|
if ( onActivateObjectTransform.gameObject.activeSelf && Time.time - pointerShowStartTime > activateObjectTime )
|
|
{
|
|
onActivateObjectTransform.gameObject.SetActive( false );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( onDeactivateObjectTransform.gameObject.activeSelf && Time.time - pointerHideStartTime > deactivateObjectTime )
|
|
{
|
|
onDeactivateObjectTransform.gameObject.SetActive( false );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private void UpdatePointer()
|
|
{
|
|
Vector3 pointerStart = pointerStartTransform.position;
|
|
Vector3 pointerEnd;
|
|
Vector3 pointerDir = pointerStartTransform.forward;
|
|
bool hitSomething = false;
|
|
bool showPlayAreaPreview = false;
|
|
Vector3 playerFeetOffset = player.trackingOriginTransform.position - player.feetPositionGuess;
|
|
|
|
Vector3 arcVelocity = pointerDir * arcDistance;
|
|
|
|
TeleportMarkerBase hitTeleportMarker = null;
|
|
|
|
//Check pointer angle
|
|
float dotUp = Vector3.Dot( pointerDir, Vector3.up );
|
|
float dotForward = Vector3.Dot( pointerDir, player.hmdTransform.forward );
|
|
bool pointerAtBadAngle = false;
|
|
if ( ( dotForward > 0 && dotUp > 0.75f ) || ( dotForward < 0.0f && dotUp > 0.5f ) )
|
|
{
|
|
pointerAtBadAngle = true;
|
|
}
|
|
|
|
//Trace to see if the pointer hit anything
|
|
RaycastHit hitInfo;
|
|
teleportArc.SetArcData( pointerStart, arcVelocity, true, pointerAtBadAngle );
|
|
if ( teleportArc.DrawArc( out hitInfo ) )
|
|
{
|
|
hitSomething = true;
|
|
hitTeleportMarker = hitInfo.collider.GetComponentInParent<TeleportMarkerBase>();
|
|
}
|
|
|
|
if ( pointerAtBadAngle )
|
|
{
|
|
hitTeleportMarker = null;
|
|
}
|
|
|
|
HighlightSelected( hitTeleportMarker );
|
|
|
|
if ( hitTeleportMarker != null ) //Hit a teleport marker
|
|
{
|
|
if ( hitTeleportMarker.locked )
|
|
{
|
|
teleportArc.SetColor( pointerLockedColor );
|
|
#if (UNITY_5_4)
|
|
pointerLineRenderer.SetColors( pointerLockedColor, pointerLockedColor );
|
|
#else
|
|
pointerLineRenderer.startColor = pointerLockedColor;
|
|
pointerLineRenderer.endColor = pointerLockedColor;
|
|
#endif
|
|
destinationReticleTransform.gameObject.SetActive( false );
|
|
}
|
|
else
|
|
{
|
|
teleportArc.SetColor( pointerValidColor );
|
|
#if (UNITY_5_4)
|
|
pointerLineRenderer.SetColors( pointerValidColor, pointerValidColor );
|
|
#else
|
|
pointerLineRenderer.startColor = pointerValidColor;
|
|
pointerLineRenderer.endColor = pointerValidColor;
|
|
#endif
|
|
destinationReticleTransform.gameObject.SetActive( hitTeleportMarker.showReticle );
|
|
}
|
|
|
|
offsetReticleTransform.gameObject.SetActive( true );
|
|
|
|
invalidReticleTransform.gameObject.SetActive( false );
|
|
|
|
pointedAtTeleportMarker = hitTeleportMarker;
|
|
pointedAtPosition = hitInfo.point;
|
|
|
|
if ( showPlayAreaMarker )
|
|
{
|
|
//Show the play area marker if this is a teleport area
|
|
TeleportArea teleportArea = pointedAtTeleportMarker as TeleportArea;
|
|
if ( teleportArea != null && !teleportArea.locked && playAreaPreviewTransform != null )
|
|
{
|
|
Vector3 offsetToUse = playerFeetOffset;
|
|
|
|
//Adjust the actual offset to prevent the play area marker from moving too much
|
|
if ( !movedFeetFarEnough )
|
|
{
|
|
float distanceFromStartingOffset = Vector3.Distance( playerFeetOffset, startingFeetOffset );
|
|
if ( distanceFromStartingOffset < 0.1f )
|
|
{
|
|
offsetToUse = startingFeetOffset;
|
|
}
|
|
else if ( distanceFromStartingOffset < 0.4f )
|
|
{
|
|
offsetToUse = Vector3.Lerp( startingFeetOffset, playerFeetOffset, ( distanceFromStartingOffset - 0.1f ) / 0.3f );
|
|
}
|
|
else
|
|
{
|
|
movedFeetFarEnough = true;
|
|
}
|
|
}
|
|
|
|
playAreaPreviewTransform.position = pointedAtPosition + offsetToUse;
|
|
|
|
showPlayAreaPreview = true;
|
|
}
|
|
}
|
|
|
|
pointerEnd = hitInfo.point;
|
|
}
|
|
else //Hit neither
|
|
{
|
|
destinationReticleTransform.gameObject.SetActive( false );
|
|
offsetReticleTransform.gameObject.SetActive( false );
|
|
|
|
teleportArc.SetColor( pointerInvalidColor );
|
|
#if (UNITY_5_4)
|
|
pointerLineRenderer.SetColors( pointerInvalidColor, pointerInvalidColor );
|
|
#else
|
|
pointerLineRenderer.startColor = pointerInvalidColor;
|
|
pointerLineRenderer.endColor = pointerInvalidColor;
|
|
#endif
|
|
invalidReticleTransform.gameObject.SetActive( !pointerAtBadAngle );
|
|
|
|
//Orient the invalid reticle to the normal of the trace hit point
|
|
Vector3 normalToUse = hitInfo.normal;
|
|
float angle = Vector3.Angle( hitInfo.normal, Vector3.up );
|
|
if ( angle < 15.0f )
|
|
{
|
|
normalToUse = Vector3.up;
|
|
}
|
|
invalidReticleTargetRotation = Quaternion.FromToRotation( Vector3.up, normalToUse );
|
|
invalidReticleTransform.rotation = Quaternion.Slerp( invalidReticleTransform.rotation, invalidReticleTargetRotation, 0.1f );
|
|
|
|
//Scale the invalid reticle based on the distance from the player
|
|
float distanceFromPlayer = Vector3.Distance( hitInfo.point, player.hmdTransform.position );
|
|
float invalidReticleCurrentScale = Util.RemapNumberClamped( distanceFromPlayer, invalidReticleMinScaleDistance, invalidReticleMaxScaleDistance, invalidReticleMinScale, invalidReticleMaxScale );
|
|
invalidReticleScale.x = invalidReticleCurrentScale;
|
|
invalidReticleScale.y = invalidReticleCurrentScale;
|
|
invalidReticleScale.z = invalidReticleCurrentScale;
|
|
invalidReticleTransform.transform.localScale = invalidReticleScale;
|
|
|
|
pointedAtTeleportMarker = null;
|
|
|
|
if ( hitSomething )
|
|
{
|
|
pointerEnd = hitInfo.point;
|
|
}
|
|
else
|
|
{
|
|
pointerEnd = teleportArc.GetArcPositionAtTime( teleportArc.arcDuration );
|
|
}
|
|
|
|
//Debug floor
|
|
if ( debugFloor )
|
|
{
|
|
floorDebugSphere.gameObject.SetActive( false );
|
|
floorDebugLine.gameObject.SetActive( false );
|
|
}
|
|
}
|
|
|
|
if ( playAreaPreviewTransform != null )
|
|
{
|
|
playAreaPreviewTransform.gameObject.SetActive( showPlayAreaPreview );
|
|
}
|
|
|
|
if ( !showOffsetReticle )
|
|
{
|
|
offsetReticleTransform.gameObject.SetActive( false );
|
|
}
|
|
|
|
destinationReticleTransform.position = pointedAtPosition;
|
|
invalidReticleTransform.position = pointerEnd;
|
|
onActivateObjectTransform.position = pointerEnd;
|
|
onDeactivateObjectTransform.position = pointerEnd;
|
|
offsetReticleTransform.position = pointerEnd - playerFeetOffset;
|
|
|
|
reticleAudioSource.transform.position = pointedAtPosition;
|
|
|
|
pointerLineRenderer.SetPosition( 0, pointerStart );
|
|
pointerLineRenderer.SetPosition( 1, pointerEnd );
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
void FixedUpdate()
|
|
{
|
|
if ( !visible )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( debugFloor )
|
|
{
|
|
//Debug floor
|
|
TeleportArea teleportArea = pointedAtTeleportMarker as TeleportArea;
|
|
if ( teleportArea != null )
|
|
{
|
|
if ( floorFixupMaximumTraceDistance > 0.0f )
|
|
{
|
|
floorDebugSphere.gameObject.SetActive( true );
|
|
floorDebugLine.gameObject.SetActive( true );
|
|
|
|
RaycastHit raycastHit;
|
|
Vector3 traceDir = Vector3.down;
|
|
traceDir.x = 0.01f;
|
|
if ( Physics.Raycast( pointedAtPosition + 0.05f * traceDir, traceDir, out raycastHit, floorFixupMaximumTraceDistance, floorFixupTraceLayerMask ) )
|
|
{
|
|
floorDebugSphere.transform.position = raycastHit.point;
|
|
floorDebugSphere.material.color = Color.green;
|
|
#if (UNITY_5_4)
|
|
floorDebugLine.SetColors( Color.green, Color.green );
|
|
#else
|
|
floorDebugLine.startColor = Color.green;
|
|
floorDebugLine.endColor = Color.green;
|
|
#endif
|
|
floorDebugLine.SetPosition( 0, pointedAtPosition );
|
|
floorDebugLine.SetPosition( 1, raycastHit.point );
|
|
}
|
|
else
|
|
{
|
|
Vector3 rayEnd = pointedAtPosition + ( traceDir * floorFixupMaximumTraceDistance );
|
|
floorDebugSphere.transform.position = rayEnd;
|
|
floorDebugSphere.material.color = Color.red;
|
|
#if (UNITY_5_4)
|
|
floorDebugLine.SetColors( Color.red, Color.red );
|
|
#else
|
|
floorDebugLine.startColor = Color.red;
|
|
floorDebugLine.endColor = Color.red;
|
|
#endif
|
|
floorDebugLine.SetPosition( 0, pointedAtPosition );
|
|
floorDebugLine.SetPosition( 1, rayEnd );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private void OnChaperoneInfoInitialized()
|
|
{
|
|
ChaperoneInfo chaperone = ChaperoneInfo.instance;
|
|
|
|
if ( chaperone.initialized && chaperone.roomscale )
|
|
{
|
|
//Set up the render model for the play area bounds
|
|
|
|
if ( playAreaPreviewTransform == null )
|
|
{
|
|
playAreaPreviewTransform = new GameObject( "PlayAreaPreviewTransform" ).transform;
|
|
playAreaPreviewTransform.parent = transform;
|
|
Util.ResetTransform( playAreaPreviewTransform );
|
|
|
|
playAreaPreviewCorner.SetActive( true );
|
|
playAreaPreviewCorners = new Transform[4];
|
|
playAreaPreviewCorners[0] = playAreaPreviewCorner.transform;
|
|
playAreaPreviewCorners[1] = Instantiate( playAreaPreviewCorners[0] );
|
|
playAreaPreviewCorners[2] = Instantiate( playAreaPreviewCorners[0] );
|
|
playAreaPreviewCorners[3] = Instantiate( playAreaPreviewCorners[0] );
|
|
|
|
playAreaPreviewCorners[0].transform.parent = playAreaPreviewTransform;
|
|
playAreaPreviewCorners[1].transform.parent = playAreaPreviewTransform;
|
|
playAreaPreviewCorners[2].transform.parent = playAreaPreviewTransform;
|
|
playAreaPreviewCorners[3].transform.parent = playAreaPreviewTransform;
|
|
|
|
playAreaPreviewSide.SetActive( true );
|
|
playAreaPreviewSides = new Transform[4];
|
|
playAreaPreviewSides[0] = playAreaPreviewSide.transform;
|
|
playAreaPreviewSides[1] = Instantiate( playAreaPreviewSides[0] );
|
|
playAreaPreviewSides[2] = Instantiate( playAreaPreviewSides[0] );
|
|
playAreaPreviewSides[3] = Instantiate( playAreaPreviewSides[0] );
|
|
|
|
playAreaPreviewSides[0].transform.parent = playAreaPreviewTransform;
|
|
playAreaPreviewSides[1].transform.parent = playAreaPreviewTransform;
|
|
playAreaPreviewSides[2].transform.parent = playAreaPreviewTransform;
|
|
playAreaPreviewSides[3].transform.parent = playAreaPreviewTransform;
|
|
}
|
|
|
|
float x = chaperone.playAreaSizeX;
|
|
float z = chaperone.playAreaSizeZ;
|
|
|
|
playAreaPreviewSides[0].localPosition = new Vector3( 0.0f, 0.0f, 0.5f * z - 0.25f );
|
|
playAreaPreviewSides[1].localPosition = new Vector3( 0.0f, 0.0f, -0.5f * z + 0.25f );
|
|
playAreaPreviewSides[2].localPosition = new Vector3( 0.5f * x - 0.25f, 0.0f, 0.0f );
|
|
playAreaPreviewSides[3].localPosition = new Vector3( -0.5f * x + 0.25f, 0.0f, 0.0f );
|
|
|
|
playAreaPreviewSides[0].localScale = new Vector3( x - 0.5f, 1.0f, 1.0f );
|
|
playAreaPreviewSides[1].localScale = new Vector3( x - 0.5f, 1.0f, 1.0f );
|
|
playAreaPreviewSides[2].localScale = new Vector3( z - 0.5f, 1.0f, 1.0f );
|
|
playAreaPreviewSides[3].localScale = new Vector3( z - 0.5f, 1.0f, 1.0f );
|
|
|
|
playAreaPreviewSides[0].localRotation = Quaternion.Euler( 0.0f, 0.0f, 0.0f );
|
|
playAreaPreviewSides[1].localRotation = Quaternion.Euler( 0.0f, 180.0f, 0.0f );
|
|
playAreaPreviewSides[2].localRotation = Quaternion.Euler( 0.0f, 90.0f, 0.0f );
|
|
playAreaPreviewSides[3].localRotation = Quaternion.Euler( 0.0f, 270.0f, 0.0f );
|
|
|
|
playAreaPreviewCorners[0].localPosition = new Vector3( 0.5f * x - 0.25f, 0.0f, 0.5f * z - 0.25f );
|
|
playAreaPreviewCorners[1].localPosition = new Vector3( 0.5f * x - 0.25f, 0.0f, -0.5f * z + 0.25f );
|
|
playAreaPreviewCorners[2].localPosition = new Vector3( -0.5f * x + 0.25f, 0.0f, -0.5f * z + 0.25f );
|
|
playAreaPreviewCorners[3].localPosition = new Vector3( -0.5f * x + 0.25f, 0.0f, 0.5f * z - 0.25f );
|
|
|
|
playAreaPreviewCorners[0].localRotation = Quaternion.Euler( 0.0f, 0.0f, 0.0f );
|
|
playAreaPreviewCorners[1].localRotation = Quaternion.Euler( 0.0f, 90.0f, 0.0f );
|
|
playAreaPreviewCorners[2].localRotation = Quaternion.Euler( 0.0f, 180.0f, 0.0f );
|
|
playAreaPreviewCorners[3].localRotation = Quaternion.Euler( 0.0f, 270.0f, 0.0f );
|
|
|
|
playAreaPreviewTransform.gameObject.SetActive( false );
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private void HidePointer()
|
|
{
|
|
if ( visible )
|
|
{
|
|
pointerHideStartTime = Time.time;
|
|
}
|
|
|
|
visible = false;
|
|
if ( pointerHand )
|
|
{
|
|
if ( ShouldOverrideHoverLock() )
|
|
{
|
|
//Restore the original hovering interactable on the hand
|
|
if ( originalHoverLockState == true )
|
|
{
|
|
pointerHand.HoverLock( originalHoveringInteractable );
|
|
}
|
|
else
|
|
{
|
|
pointerHand.HoverUnlock( null );
|
|
}
|
|
}
|
|
|
|
//Stop looping sound
|
|
loopingAudioSource.Stop();
|
|
PlayAudioClip( pointerAudioSource, pointerStopSound );
|
|
}
|
|
teleportPointerObject.SetActive( false );
|
|
|
|
teleportArc.Hide();
|
|
|
|
foreach ( TeleportMarkerBase teleportMarker in teleportMarkers )
|
|
{
|
|
if ( teleportMarker != null && teleportMarker.markerActive && teleportMarker.gameObject != null )
|
|
{
|
|
teleportMarker.gameObject.SetActive( false );
|
|
}
|
|
}
|
|
|
|
destinationReticleTransform.gameObject.SetActive( false );
|
|
invalidReticleTransform.gameObject.SetActive( false );
|
|
offsetReticleTransform.gameObject.SetActive( false );
|
|
|
|
if ( playAreaPreviewTransform != null )
|
|
{
|
|
playAreaPreviewTransform.gameObject.SetActive( false );
|
|
}
|
|
|
|
if ( onActivateObjectTransform.gameObject.activeSelf )
|
|
{
|
|
onActivateObjectTransform.gameObject.SetActive( false );
|
|
}
|
|
onDeactivateObjectTransform.gameObject.SetActive( true );
|
|
|
|
pointerHand = null;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private void ShowPointer( Hand newPointerHand, Hand oldPointerHand )
|
|
{
|
|
if ( !visible )
|
|
{
|
|
pointedAtTeleportMarker = null;
|
|
pointerShowStartTime = Time.time;
|
|
visible = true;
|
|
meshFading = true;
|
|
|
|
teleportPointerObject.SetActive( false );
|
|
teleportArc.Show();
|
|
|
|
foreach ( TeleportMarkerBase teleportMarker in teleportMarkers )
|
|
{
|
|
if ( teleportMarker.markerActive && teleportMarker.ShouldActivate( player.feetPositionGuess ) )
|
|
{
|
|
teleportMarker.gameObject.SetActive( true );
|
|
teleportMarker.Highlight( false );
|
|
}
|
|
}
|
|
|
|
startingFeetOffset = player.trackingOriginTransform.position - player.feetPositionGuess;
|
|
movedFeetFarEnough = false;
|
|
|
|
if ( onDeactivateObjectTransform.gameObject.activeSelf )
|
|
{
|
|
onDeactivateObjectTransform.gameObject.SetActive( false );
|
|
}
|
|
onActivateObjectTransform.gameObject.SetActive( true );
|
|
|
|
loopingAudioSource.clip = pointerLoopSound;
|
|
loopingAudioSource.loop = true;
|
|
loopingAudioSource.Play();
|
|
loopingAudioSource.volume = 0.0f;
|
|
}
|
|
|
|
|
|
if ( oldPointerHand )
|
|
{
|
|
if ( ShouldOverrideHoverLock() )
|
|
{
|
|
//Restore the original hovering interactable on the hand
|
|
if ( originalHoverLockState == true )
|
|
{
|
|
oldPointerHand.HoverLock( originalHoveringInteractable );
|
|
}
|
|
else
|
|
{
|
|
oldPointerHand.HoverUnlock( null );
|
|
}
|
|
}
|
|
}
|
|
|
|
pointerHand = newPointerHand;
|
|
|
|
if ( visible && oldPointerHand != pointerHand )
|
|
{
|
|
PlayAudioClip( pointerAudioSource, pointerStartSound );
|
|
}
|
|
|
|
if ( pointerHand )
|
|
{
|
|
pointerStartTransform = GetPointerStartTransform( pointerHand );
|
|
|
|
if ( pointerHand.currentAttachedObject != null )
|
|
{
|
|
allowTeleportWhileAttached = pointerHand.currentAttachedObject.GetComponent<AllowTeleportWhileAttachedToHand>();
|
|
}
|
|
|
|
//Keep track of any existing hovering interactable on the hand
|
|
originalHoverLockState = pointerHand.hoverLocked;
|
|
originalHoveringInteractable = pointerHand.hoveringInteractable;
|
|
|
|
if ( ShouldOverrideHoverLock() )
|
|
{
|
|
pointerHand.HoverLock( null );
|
|
}
|
|
|
|
pointerAudioSource.transform.SetParent( pointerStartTransform );
|
|
pointerAudioSource.transform.localPosition = Vector3.zero;
|
|
|
|
loopingAudioSource.transform.SetParent( pointerStartTransform );
|
|
loopingAudioSource.transform.localPosition = Vector3.zero;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private void UpdateTeleportColors()
|
|
{
|
|
float deltaTime = Time.time - pointerShowStartTime;
|
|
if ( deltaTime > meshFadeTime )
|
|
{
|
|
meshAlphaPercent = 1.0f;
|
|
meshFading = false;
|
|
}
|
|
else
|
|
{
|
|
meshAlphaPercent = Mathf.Lerp( 0.0f, 1.0f, deltaTime / meshFadeTime );
|
|
}
|
|
|
|
//Tint color for the teleport points
|
|
foreach ( TeleportMarkerBase teleportMarker in teleportMarkers )
|
|
{
|
|
teleportMarker.SetAlpha( fullTintAlpha * meshAlphaPercent, meshAlphaPercent );
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private void PlayAudioClip( AudioSource source, AudioClip clip )
|
|
{
|
|
source.clip = clip;
|
|
source.Play();
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private void PlayPointerHaptic( bool validLocation )
|
|
{
|
|
if ( pointerHand.controller != null )
|
|
{
|
|
if ( validLocation )
|
|
{
|
|
pointerHand.controller.TriggerHapticPulse( 800 );
|
|
}
|
|
else
|
|
{
|
|
pointerHand.controller.TriggerHapticPulse( 100 );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private void TryTeleportPlayer()
|
|
{
|
|
if ( visible && !teleporting )
|
|
{
|
|
if ( pointedAtTeleportMarker != null && pointedAtTeleportMarker.locked == false )
|
|
{
|
|
//Pointing at an unlocked teleport marker
|
|
teleportingToMarker = pointedAtTeleportMarker;
|
|
InitiateTeleportFade();
|
|
|
|
CancelTeleportHint();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private void InitiateTeleportFade()
|
|
{
|
|
teleporting = true;
|
|
|
|
currentFadeTime = teleportFadeTime;
|
|
|
|
TeleportPoint teleportPoint = teleportingToMarker as TeleportPoint;
|
|
if ( teleportPoint != null && teleportPoint.teleportType == TeleportPoint.TeleportPointType.SwitchToNewScene )
|
|
{
|
|
currentFadeTime *= 3.0f;
|
|
Teleport.ChangeScene.Send( currentFadeTime );
|
|
}
|
|
|
|
SteamVR_Fade.Start( Color.clear, 0 );
|
|
SteamVR_Fade.Start( Color.black, currentFadeTime );
|
|
|
|
headAudioSource.transform.SetParent( player.hmdTransform );
|
|
headAudioSource.transform.localPosition = Vector3.zero;
|
|
PlayAudioClip( headAudioSource, teleportSound );
|
|
|
|
Invoke( "TeleportPlayer", currentFadeTime );
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private void TeleportPlayer()
|
|
{
|
|
teleporting = false;
|
|
|
|
Teleport.PlayerPre.Send( pointedAtTeleportMarker );
|
|
|
|
SteamVR_Fade.Start( Color.clear, currentFadeTime );
|
|
|
|
TeleportPoint teleportPoint = teleportingToMarker as TeleportPoint;
|
|
Vector3 teleportPosition = pointedAtPosition;
|
|
|
|
if ( teleportPoint != null )
|
|
{
|
|
teleportPosition = teleportPoint.transform.position;
|
|
|
|
//Teleport to a new scene
|
|
if ( teleportPoint.teleportType == TeleportPoint.TeleportPointType.SwitchToNewScene )
|
|
{
|
|
teleportPoint.TeleportToScene();
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Find the actual floor position below the navigation mesh
|
|
TeleportArea teleportArea = teleportingToMarker as TeleportArea;
|
|
if ( teleportArea != null )
|
|
{
|
|
if ( floorFixupMaximumTraceDistance > 0.0f )
|
|
{
|
|
RaycastHit raycastHit;
|
|
if ( Physics.Raycast( teleportPosition + 0.05f * Vector3.down, Vector3.down, out raycastHit, floorFixupMaximumTraceDistance, floorFixupTraceLayerMask ) )
|
|
{
|
|
teleportPosition = raycastHit.point;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( teleportingToMarker.ShouldMovePlayer() )
|
|
{
|
|
Vector3 playerFeetOffset = player.trackingOriginTransform.position - player.feetPositionGuess;
|
|
player.trackingOriginTransform.position = teleportPosition + playerFeetOffset;
|
|
}
|
|
else
|
|
{
|
|
teleportingToMarker.TeleportPlayer( pointedAtPosition );
|
|
}
|
|
|
|
Teleport.Player.Send( pointedAtTeleportMarker );
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private void HighlightSelected( TeleportMarkerBase hitTeleportMarker )
|
|
{
|
|
if ( pointedAtTeleportMarker != hitTeleportMarker ) //Pointing at a new teleport marker
|
|
{
|
|
if ( pointedAtTeleportMarker != null )
|
|
{
|
|
pointedAtTeleportMarker.Highlight( false );
|
|
}
|
|
|
|
if ( hitTeleportMarker != null )
|
|
{
|
|
hitTeleportMarker.Highlight( true );
|
|
|
|
prevPointedAtPosition = pointedAtPosition;
|
|
PlayPointerHaptic( !hitTeleportMarker.locked );
|
|
|
|
PlayAudioClip( reticleAudioSource, goodHighlightSound );
|
|
|
|
loopingAudioSource.volume = loopingAudioMaxVolume;
|
|
}
|
|
else if ( pointedAtTeleportMarker != null )
|
|
{
|
|
PlayAudioClip( reticleAudioSource, badHighlightSound );
|
|
|
|
loopingAudioSource.volume = 0.0f;
|
|
}
|
|
}
|
|
else if ( hitTeleportMarker != null ) //Pointing at the same teleport marker
|
|
{
|
|
if ( Vector3.Distance( prevPointedAtPosition, pointedAtPosition ) > 1.0f )
|
|
{
|
|
prevPointedAtPosition = pointedAtPosition;
|
|
PlayPointerHaptic( !hitTeleportMarker.locked );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
public void ShowTeleportHint()
|
|
{
|
|
CancelTeleportHint();
|
|
|
|
hintCoroutine = StartCoroutine( TeleportHintCoroutine() );
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
public void CancelTeleportHint()
|
|
{
|
|
if ( hintCoroutine != null )
|
|
{
|
|
foreach ( Hand hand in player.hands )
|
|
{
|
|
ControllerButtonHints.HideTextHint( hand, EVRButtonId.k_EButton_SteamVR_Touchpad );
|
|
}
|
|
|
|
StopCoroutine( hintCoroutine );
|
|
hintCoroutine = null;
|
|
}
|
|
|
|
CancelInvoke( "ShowTeleportHint" );
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private IEnumerator TeleportHintCoroutine()
|
|
{
|
|
float prevBreakTime = Time.time;
|
|
float prevHapticPulseTime = Time.time;
|
|
|
|
while ( true )
|
|
{
|
|
bool pulsed = false;
|
|
|
|
//Show the hint on each eligible hand
|
|
foreach ( Hand hand in player.hands )
|
|
{
|
|
bool showHint = IsEligibleForTeleport( hand );
|
|
bool isShowingHint = !string.IsNullOrEmpty( ControllerButtonHints.GetActiveHintText( hand, EVRButtonId.k_EButton_SteamVR_Touchpad ) );
|
|
if ( showHint )
|
|
{
|
|
if ( !isShowingHint )
|
|
{
|
|
ControllerButtonHints.ShowTextHint( hand, EVRButtonId.k_EButton_SteamVR_Touchpad, "Teleport" );
|
|
prevBreakTime = Time.time;
|
|
prevHapticPulseTime = Time.time;
|
|
}
|
|
|
|
if ( Time.time > prevHapticPulseTime + 0.05f )
|
|
{
|
|
//Haptic pulse for a few seconds
|
|
pulsed = true;
|
|
|
|
hand.controller.TriggerHapticPulse( 500 );
|
|
}
|
|
}
|
|
else if ( !showHint && isShowingHint )
|
|
{
|
|
ControllerButtonHints.HideTextHint( hand, EVRButtonId.k_EButton_SteamVR_Touchpad );
|
|
}
|
|
}
|
|
|
|
if ( Time.time > prevBreakTime + 3.0f )
|
|
{
|
|
//Take a break for a few seconds
|
|
yield return new WaitForSeconds( 3.0f );
|
|
|
|
prevBreakTime = Time.time;
|
|
}
|
|
|
|
if ( pulsed )
|
|
{
|
|
prevHapticPulseTime = Time.time;
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
public bool IsEligibleForTeleport( Hand hand )
|
|
{
|
|
if ( hand == null )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( !hand.gameObject.activeInHierarchy )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( hand.hoveringInteractable != null )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( hand.noSteamVRFallbackCamera == null )
|
|
{
|
|
if ( hand.controller == null )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//Something is attached to the hand
|
|
if ( hand.currentAttachedObject != null )
|
|
{
|
|
AllowTeleportWhileAttachedToHand allowTeleportWhileAttachedToHand = hand.currentAttachedObject.GetComponent<AllowTeleportWhileAttachedToHand>();
|
|
|
|
if ( allowTeleportWhileAttachedToHand != null && allowTeleportWhileAttachedToHand.teleportAllowed == true )
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private bool ShouldOverrideHoverLock()
|
|
{
|
|
if ( !allowTeleportWhileAttached || allowTeleportWhileAttached.overrideHoverLock )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private bool WasTeleportButtonReleased( Hand hand )
|
|
{
|
|
if ( IsEligibleForTeleport( hand ) )
|
|
{
|
|
if ( hand.noSteamVRFallbackCamera != null )
|
|
{
|
|
return Input.GetKeyUp( KeyCode.T );
|
|
}
|
|
else
|
|
{
|
|
return hand.controller.GetPressUp( SteamVR_Controller.ButtonMask.Touchpad );
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private bool IsTeleportButtonDown( Hand hand )
|
|
{
|
|
if ( IsEligibleForTeleport( hand ) )
|
|
{
|
|
if ( hand.noSteamVRFallbackCamera != null )
|
|
{
|
|
return Input.GetKey( KeyCode.T );
|
|
}
|
|
else
|
|
{
|
|
return hand.controller.GetPress( SteamVR_Controller.ButtonMask.Touchpad );
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private bool WasTeleportButtonPressed( Hand hand )
|
|
{
|
|
if ( IsEligibleForTeleport( hand ) )
|
|
{
|
|
if ( hand.noSteamVRFallbackCamera != null )
|
|
{
|
|
return Input.GetKeyDown( KeyCode.T );
|
|
}
|
|
else
|
|
{
|
|
return hand.controller.GetPressDown( SteamVR_Controller.ButtonMask.Touchpad );
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
private Transform GetPointerStartTransform( Hand hand )
|
|
{
|
|
if ( hand.noSteamVRFallbackCamera != null )
|
|
{
|
|
return hand.noSteamVRFallbackCamera.transform;
|
|
}
|
|
else
|
|
{
|
|
return pointerHand.GetAttachmentTransform( "Attach_ControllerTip" );
|
|
}
|
|
}
|
|
}
|
|
}
|