B-Squared
B-Squared

Reputation: 35

Unity HTC VIVE Teleportation

I am developing for the HTC VIVE and am trying to create a teleportation script that would allow the user to teleport to a certain location (predefined by me) when the user grabs a certain object. I currently have a teleportation code that works like a normal teleporter where the user points at a location and the room is moved to that location. I have modified this so that no matter where the user is pointing they will always teleport to the specific location. This is a first step but I am really looking to trigger this teleportation when the user picks up a certain object, does anyone have any ideas on where to star or how to do this?

Here is the code for the modified teleporter:

namespace VRTK{
using UnityEngine;
using System.Collections;

public delegate void TeleportEventHandler(object sender, DestinationMarkerEventArgs e);

public class VRTK_BasicTeleport : MonoBehaviour
{
    public float blinkTransitionSpeed = 0.6f;
    [Range(0f, 32f)]
    public float distanceBlinkDelay = 0f;
    public bool headsetPositionCompensation = true;
    public string ignoreTargetWithTagOrClass;
    public bool limitToNavMesh = false;

    public event TeleportEventHandler Teleporting;
    public event TeleportEventHandler Teleported;

    protected Transform eyeCamera;
    protected bool adjustYForTerrain = false;
    protected bool enableTeleport = true;

    private float blinkPause = 0f;
    private float fadeInTime = 0f;
    private float maxBlinkTransitionSpeed = 1.5f;
    private float maxBlinkDistance = 33f;

    public void InitDestinationSetListener(GameObject markerMaker)
    {
        if (markerMaker)
        {
            foreach (var worldMarker in markerMaker.GetComponents<VRTK_DestinationMarker>())
            {
                worldMarker.DestinationMarkerSet += new DestinationMarkerEventHandler(DoTeleport);
                worldMarker.SetInvalidTarget(ignoreTargetWithTagOrClass);
                worldMarker.SetNavMeshCheck(limitToNavMesh);
                worldMarker.SetHeadsetPositionCompensation(headsetPositionCompensation);
            }
        }
    }

    protected virtual void Start()
    {
        Utilities.SetPlayerObject(this.gameObject, VRTK_PlayerObject.ObjectTypes.CameraRig);

        adjustYForTerrain = false;
        eyeCamera = Utilities.AddCameraFade();

        InitDestinationMarkerListeners();
        InitHeadsetCollisionListener();

        enableTeleport = true;
    }

    protected void OnTeleporting(object sender, DestinationMarkerEventArgs e)
    {
        if (Teleporting != null)
            Teleporting(this, e);
    }

    protected void OnTeleported(object sender, DestinationMarkerEventArgs e)
    {
        if (Teleported != null)
            Teleported(this, e);
    }

    protected virtual void Blink(float transitionSpeed)
    {
        fadeInTime = transitionSpeed;
        SteamVR_Fade.Start(Color.black, 0);
        Invoke("ReleaseBlink", blinkPause);
    }

    protected virtual bool ValidLocation(Transform target)
    {
        //If the target is one of the player objects or a UI Canvas then it's never a valid location
        if(target.GetComponent<VRTK_PlayerObject>() || target.GetComponent<VRTK_UIGraphicRaycaster>())
        {
            return false;
        }

        bool validNavMeshLocation = false;
        if (target)
        {
            NavMeshHit hit;
            validNavMeshLocation = NavMesh.SamplePosition(target.position, out hit, 1.0f, NavMesh.AllAreas);
        }
        if (!limitToNavMesh)
        {
            validNavMeshLocation = true;
        }

        return (validNavMeshLocation && target && target.tag != ignoreTargetWithTagOrClass && target.GetComponent(ignoreTargetWithTagOrClass) == null);
    }

    protected virtual void DoTeleport(object sender, DestinationMarkerEventArgs e)
    {
        if (enableTeleport && ValidLocation(e.target) && e.enableTeleport)
        {
            OnTeleporting(sender, e);
            Vector3 newPosition = GetNewPosition(e.destinationPosition, e.target);
            CalculateBlinkDelay(blinkTransitionSpeed, newPosition);
            Blink(blinkTransitionSpeed);
            SetNewPosition(newPosition, e.target);
            OnTeleported(sender, e);
        }
    }

    protected virtual void SetNewPosition(Vector3 position, Transform target)
    {
        this.transform.position = CheckTerrainCollision(position, target);
    }

    protected virtual Vector3 GetNewPosition(Vector3 tipPosition, Transform target)
    {
        float newX = 0;
        float newY = 17;
        float newZ = 0;

        return new Vector3(newX, newY, newZ);
    }

    protected Vector3 CheckTerrainCollision(Vector3 position, Transform target)
    {
        if (adjustYForTerrain && target.GetComponent<Terrain>())
        {
            var terrainHeight = Terrain.activeTerrain.SampleHeight(position);
            position.y = (terrainHeight > position.y ? position.y : terrainHeight);
        }
        return position;
    }

    private void CalculateBlinkDelay(float blinkSpeed, Vector3 newPosition)
    {
        blinkPause = 0f;
        if (distanceBlinkDelay > 0f)
        {
            float distance = Vector3.Distance(this.transform.position, newPosition);
            blinkPause = Mathf.Clamp((distance * blinkTransitionSpeed) / (maxBlinkDistance - distanceBlinkDelay), 0, maxBlinkTransitionSpeed);
            blinkPause = (blinkSpeed <= 0.25 ? 0f : blinkPause);
        }
    }

    private void ReleaseBlink()
    {
        SteamVR_Fade.Start(Color.clear, fadeInTime);
        fadeInTime = 0f;
    }

    private void InitDestinationMarkerListeners()
    {
        var controllerManager = GameObject.FindObjectOfType<SteamVR_ControllerManager>();
        InitDestinationSetListener(controllerManager.left);
        InitDestinationSetListener(controllerManager.right);

        foreach (var destinationMarker in GameObject.FindObjectsOfType<VRTK_DestinationMarker>())
        {
            if (destinationMarker.gameObject != controllerManager.left && destinationMarker.gameObject != controllerManager.right)
            {
                InitDestinationSetListener(destinationMarker.gameObject);
            }
        }
    }

    private void InitHeadsetCollisionListener()
    {
        var headset = GameObject.FindObjectOfType<VRTK_HeadsetCollisionFade>();
        if (headset)
        {
            headset.HeadsetCollisionDetect += new HeadsetCollisionEventHandler(DisableTeleport);
            headset.HeadsetCollisionEnded += new HeadsetCollisionEventHandler(EnableTeleport);
        }
    }

    private void DisableTeleport(object sender, HeadsetCollisionEventArgs e)
    {
        enableTeleport = false;
    }

    private void EnableTeleport(object sender, HeadsetCollisionEventArgs e)
    {
        enableTeleport = true;
    }
}

And here is the code for the pointer:

namespace VRTK{
using UnityEngine;
using System.Collections;

public class VRTK_BezierPointer : VRTK_WorldPointer
{
    public float pointerLength = 10f;
    public int pointerDensity = 10;
    public bool showPointerCursor = true;
    public float pointerCursorRadius = 0.5f;
    public float beamCurveOffset = 1f;
    public GameObject customPointerTracer;
    public GameObject customPointerCursor;
    public LayerMask layersToIgnore = Physics.IgnoreRaycastLayer;

    private GameObject projectedBeamContainer;
    private GameObject projectedBeamForward;
    private GameObject projectedBeamJoint;
    private GameObject projectedBeamDown;

    private GameObject pointerCursor;
    private GameObject curvedBeamContainer;
    private CurveGenerator curvedBeam;

    // Use this for initialization
    protected override void Start()
    {
        base.Start();
        InitProjectedBeams();
        InitPointer();
        TogglePointer(false);
    }

    protected override void Update()
    {
        base.Update();
        if (projectedBeamForward.gameObject.activeSelf)
        {
            ProjectForwardBeam();
            ProjectDownBeam();
            DisplayCurvedBeam();
            SetPointerCursor();
        }
    }

    protected override void InitPointer()
    {
        pointerCursor = (customPointerCursor ? Instantiate(customPointerCursor) : CreateCursor());

        pointerCursor.name = string.Format("[{0}]WorldPointer_BezierPointer_PointerCursor", this.gameObject.name);
        Utilities.SetPlayerObject(pointerCursor, VRTK_PlayerObject.ObjectTypes.Pointer);
        pointerCursor.layer = LayerMask.NameToLayer("Ignore Raycast");
        pointerCursor.SetActive(false);

        curvedBeamContainer = new GameObject(string.Format("[{0}]WorldPointer_BezierPointer_CurvedBeamContainer", this.gameObject.name));
        Utilities.SetPlayerObject(curvedBeamContainer, VRTK_PlayerObject.ObjectTypes.Pointer);
        curvedBeamContainer.SetActive(false);
        curvedBeam = curvedBeamContainer.gameObject.AddComponent<CurveGenerator>();
        curvedBeam.transform.parent = null;
        curvedBeam.Create(pointerDensity, pointerCursorRadius, customPointerTracer);
        base.InitPointer();
    }

    protected override void SetPointerMaterial()
    {
        if (pointerCursor.GetComponent<Renderer>())
        {
            pointerCursor.GetComponent<Renderer>().material = pointerMaterial;
        }

        foreach (Renderer mr in pointerCursor.GetComponentsInChildren<Renderer>())
        {
            mr.material = pointerMaterial;
        }

        base.SetPointerMaterial();
    }

    protected override void TogglePointer(bool state)
    {
        state = (pointerVisibility == pointerVisibilityStates.Always_On ? true : state);

        projectedBeamForward.gameObject.SetActive(state);
        projectedBeamJoint.gameObject.SetActive(state);
        projectedBeamDown.SetActive(state);
    }

    protected override void DisablePointerBeam(object sender, ControllerInteractionEventArgs e)
    {
        base.DisablePointerBeam(sender, e);
        TogglePointerCursor(false);
        curvedBeam.TogglePoints(false);
    }

    protected override void OnDestroy()
    {
        base.OnDestroy();
        if (projectedBeamDown != null)
        {
            Destroy(projectedBeamDown);
        }
        if (pointerCursor != null)
        {
            Destroy(pointerCursor);
        }
        if (curvedBeam != null)
        {
            Destroy(curvedBeam);
        }
        if (projectedBeamContainer != null)
        {
            Destroy(projectedBeamContainer);
        }
        if (curvedBeamContainer != null)
        {
            Destroy(curvedBeamContainer);
        }
    }

    private GameObject CreateCursor()
    {
        var cursorYOffset = 0.02f;
        var cursor = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
        cursor.GetComponent<MeshRenderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
        cursor.GetComponent<MeshRenderer>().receiveShadows = false;
        cursor.transform.localScale = new Vector3(pointerCursorRadius, cursorYOffset, pointerCursorRadius);
        Destroy(cursor.GetComponent<CapsuleCollider>());
        return cursor;
    }

    private void TogglePointerCursor(bool state)
    {
        var pointerCursorState = (showPointerCursor && state ? showPointerCursor : false);
        var playAreaCursorState = (showPlayAreaCursor && state ? showPlayAreaCursor : false);
        pointerCursor.gameObject.SetActive(pointerCursorState);
        base.TogglePointer(playAreaCursorState);
    }

    private void InitProjectedBeams()
    {
        projectedBeamContainer = new GameObject(string.Format("[{0}]WorldPointer_BezierPointer_ProjectedBeamContainer", this.gameObject.name));
        Utilities.SetPlayerObject(projectedBeamContainer, VRTK_PlayerObject.ObjectTypes.Pointer);
        projectedBeamContainer.transform.parent = this.transform;
        projectedBeamContainer.transform.localPosition = Vector3.zero;

        projectedBeamForward = new GameObject(string.Format("[{0}]WorldPointer_BezierPointer_ProjectedBeamForward", this.gameObject.name));
        Utilities.SetPlayerObject(projectedBeamForward, VRTK_PlayerObject.ObjectTypes.Pointer);
        projectedBeamForward.transform.parent = projectedBeamContainer.transform;

        projectedBeamJoint = new GameObject(string.Format("[{0}]WorldPointer_BezierPointer_ProjectedBeamJoint", this.gameObject.name));
        Utilities.SetPlayerObject(projectedBeamJoint, VRTK_PlayerObject.ObjectTypes.Pointer);
        projectedBeamJoint.transform.parent = projectedBeamContainer.transform;
        projectedBeamJoint.transform.localScale = new Vector3(0.01f, 0.01f, 0.01f);

        projectedBeamDown = new GameObject(string.Format("[{0}]WorldPointer_BezierPointer_ProjectedBeamDown", this.gameObject.name));
        Utilities.SetPlayerObject(projectedBeamDown, VRTK_PlayerObject.ObjectTypes.Pointer);
    }

    private float GetForwardBeamLength()
    {
        var actualLength = pointerLength;
        Ray pointerRaycast = new Ray(transform.position, transform.forward);
        RaycastHit collidedWith;
        var hasRayHit = Physics.Raycast(pointerRaycast, out collidedWith, pointerLength, ~layersToIgnore);

        //reset if beam not hitting or hitting new target
        if (!hasRayHit || (pointerContactTarget && pointerContactTarget != collidedWith.transform))
        {
            pointerContactDistance = 0f;
        }

        //check if beam has hit a new target
        if (hasRayHit)
        {
            pointerContactDistance = collidedWith.distance;
        }

        //adjust beam length if something is blocking it
        if (hasRayHit && pointerContactDistance < pointerLength)
        {
            actualLength = pointerContactDistance;
        }

        return actualLength;
    }

    private void ProjectForwardBeam()
    {
        var setThicknes = 0.01f;
        var setLength = GetForwardBeamLength();
        //if the additional decimal isn't added then the beam position glitches
        var beamPosition = setLength / (2 + 0.00001f);

        projectedBeamForward.transform.localScale = new Vector3(setThicknes, setThicknes, setLength);
        projectedBeamForward.transform.localPosition = new Vector3(0f, 0f, beamPosition);
        projectedBeamJoint.transform.localPosition = new Vector3(0f, 0f, setLength - (projectedBeamJoint.transform.localScale.z / 2));
        projectedBeamContainer.transform.localRotation = Quaternion.identity;
    }

    private void ProjectDownBeam()
    {
        projectedBeamDown.transform.position = new Vector3(projectedBeamJoint.transform.position.x, projectedBeamJoint.transform.position.y, projectedBeamJoint.transform.position.z);

        Ray projectedBeamDownRaycast = new Ray(projectedBeamDown.transform.position, Vector3.down);
        RaycastHit collidedWith;

        var downRayHit = Physics.Raycast(projectedBeamDownRaycast, out collidedWith, float.PositiveInfinity, ~layersToIgnore);

        if (!downRayHit || (pointerContactTarget && pointerContactTarget != collidedWith.transform))
        {
            if (pointerContactTarget != null)
            {
                base.PointerOut();
            }
            pointerContactTarget = null;
            destinationPosition = Vector3.zero;
        }

        if (downRayHit)
        {
            projectedBeamDown.transform.position = new Vector3(projectedBeamJoint.transform.position.x, projectedBeamJoint.transform.position.y - collidedWith.distance, projectedBeamJoint.transform.position.z);
            projectedBeamDown.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
            pointerContactTarget = collidedWith.transform;
            destinationPosition = projectedBeamDown.transform.position;

            base.PointerIn();
        }
    }

    private void SetPointerCursor()
    {
        if (pointerContactTarget != null)
        {
            TogglePointerCursor(true);
            pointerCursor.transform.position = projectedBeamDown.transform.position;
            base.SetPlayAreaCursorTransform(pointerCursor.transform.position);
            UpdatePointerMaterial(pointerHitColor);
        }
        else
        {
            TogglePointerCursor(false);
            UpdatePointerMaterial(pointerMissColor);
        }
    }

    private void DisplayCurvedBeam()
    {
        Vector3[] beamPoints = new Vector3[]
        {
            this.transform.position,
            projectedBeamJoint.transform.position + new Vector3(0f, beamCurveOffset, 0f),
            projectedBeamDown.transform.position,
            projectedBeamDown.transform.position,
        };

        curvedBeam.SetPoints(beamPoints, pointerMaterial);
        if (pointerVisibility != pointerVisibilityStates.Always_Off)
        {
            curvedBeam.TogglePoints(true);
        }
    }
}
}

Upvotes: 2

Views: 1429

Answers (1)

adityasinghraghav
adityasinghraghav

Reputation: 534

How are you trying to pick the object. Do you use some sort of ray cast or just pick up on collision ? Nevertheless whatever you want to do triggering the teleportation when the object is picked up should be as simple as calling the teleport script from whatever script you using to pick up the object. for eg:

void OnTriggerEnter(Collider other) 
    {
        if (other.gameObject.CompareTag ("Pick Up"))
        {
            <<call your teleport script here>>
        }
    }

Unity has really nice documentation for scripting and you can find a lot of tutorials that explain the basics, even if you go through one of them you should be able to do mostly anything you want with relative ease.

Upvotes: 1

Related Questions