26 VR開發(fā)—— HTC Vive瞬移功能的實(shí)現(xiàn)

一、為什么要實(shí)現(xiàn)瞬移這個(gè)功能##

因?yàn)镠TC Vive活動(dòng)范圍有限制(3m * 5m),所以我們?cè)趯?shí)際的使用中,為了更好的瀏覽場(chǎng)景,查看場(chǎng)景,會(huì)使用這種移動(dòng)的方式,達(dá)到游戲中的視野移動(dòng)。
一般來說就是手柄選取一個(gè)位置,通過扳機(jī)鍵確認(rèn)移動(dòng)。
移動(dòng)的方式有兩種:一種是水平移動(dòng)即X,Z軸移動(dòng);另一種就是垂直移動(dòng),即Y軸移動(dòng)。

二、實(shí)現(xiàn)過程##

這瞬移過程中最重要的是拿到目標(biāo)位置的坐標(biāo),我們可以通過射線檢測(cè)拿到位置.
在Steam VR插件給我們提供了封裝好的類與方法,我們做出相應(yīng)的改變得到我們需要的結(jié)果.
射線檢測(cè)腳本
重寫代碼展示:
using UnityEngine;
using System.Collections;

//public struct PointerEventArgs
//{
//    public uint controllerIndex;
//    public uint flags;
//    public float distance;
//    public Transform target;
//}

//public delegate void PointerEventHandler(object sender, PointerEventArgs e);



public class Test_LaserPointer : MonoBehaviour
{
    public bool active = true;
    public Color color;
    public float thickness = 0.002f;
    public GameObject holder;
    public GameObject pointer;
    bool isActive = false;
    public bool addRigidBody = false;
    public Transform reference;
    public event PointerEventHandler PointerIn;
    public event PointerEventHandler PointerOut;

    public Vector3 HitPoint;//添加的量找到目標(biāo)位置
    Transform previousContact = null;

    // Use this for initialization
    void Start ()
    {
        holder = new GameObject();
        holder.transform.parent = this.transform;
        holder.transform.localPosition = Vector3.zero;
        holder.transform.localRotation = Quaternion.identity;

        pointer = GameObject.CreatePrimitive(PrimitiveType.Cube);
        pointer.transform.parent = holder.transform;
        pointer.transform.localScale = new Vector3(thickness, thickness, 100f);
        pointer.transform.localPosition = new Vector3(0f, 0f, 50f);
        pointer.transform.localRotation = Quaternion.identity;
        BoxCollider collider = pointer.GetComponent<BoxCollider>();
        if (addRigidBody)
        {
            if (collider)
            {
                collider.isTrigger = true;
            }
            Rigidbody rigidBody = pointer.AddComponent<Rigidbody>();
            rigidBody.isKinematic = true;
        }
        else
        {
            if(collider)
            {
                Object.Destroy(collider);
            }
        }
        Material newMaterial = new Material(Shader.Find("Unlit/Color"));
        newMaterial.SetColor("_Color", color);
        pointer.GetComponent<MeshRenderer>().material = newMaterial;
    }

    public virtual void OnPointerIn(PointerEventArgs e)
    {
        if (PointerIn != null)
            PointerIn(this, e);
    }

    public virtual void OnPointerOut(PointerEventArgs e)
    {
        if (PointerOut != null)
            PointerOut(this, e);
    }


    // Update is called once per frame
    void Update ()
    {
        if (!isActive)
        {
            isActive = true;
            this.transform.GetChild(0).gameObject.SetActive(true);
        }

        float dist = 100f;

        SteamVR_TrackedController controller = GetComponent<SteamVR_TrackedController>();

        Ray raycast = new Ray(transform.position, transform.forward);
        RaycastHit hit;
        bool bHit = Physics.Raycast(raycast, out hit);

        if(previousContact && previousContact != hit.transform)
        {
            PointerEventArgs args = new PointerEventArgs();
            if (controller != null)
            {
                args.controllerIndex = controller.controllerIndex;
            }
            args.distance = 0f;
            args.flags = 0;
            args.target = previousContact;
            OnPointerOut(args);
            previousContact = null;
        }
        if(bHit && previousContact != hit.transform)
        {
            PointerEventArgs argsIn = new PointerEventArgs();
            if (controller != null)
            {
                argsIn.controllerIndex = controller.controllerIndex;
            }
            argsIn.distance = hit.distance;
            argsIn.flags = 0;
            argsIn.target = hit.transform;
            OnPointerIn(argsIn);
            previousContact = hit.transform;
        }
        if(!bHit)
        {
            previousContact = null;
        }
        if (bHit && hit.distance < 100f)
        {
            dist = hit.distance;
        }

        if (bHit)//添加的實(shí)現(xiàn)代碼;
        {
            HitPoint = hit.point;
        }

        if (controller != null && controller.triggerPressed)
        {
            pointer.transform.localScale = new Vector3(thickness * 5f, thickness * 5f, dist);
        }
        else
        {
            pointer.transform.localScale = new Vector3(thickness, thickness, dist);
        }
        pointer.transform.localPosition = new Vector3(0f, 0f, dist/2f);
    }
}

SteamVR_TrackedController腳本
下面就是自己寫代碼實(shí)現(xiàn)瞬移過程:
代碼展示及邏輯:
public class Test_Teleporter : MonoBehaviour {

    // 拿到手柄對(duì)象
    public GameObject LeftController;
    //修改后的射線檢測(cè)腳本
    private Test_LaserPointer Pointer;
    // 右手柄的控制器
    private SteamVR_TrackedController LeftSt;
    // 事件調(diào)用函數(shù)
    ClickedEventHandler ce;
    // 當(dāng)前的目標(biāo)位置
    Transform currentTransform;
    // 碰撞事件
    PointerEventArgs arg;
    void Start()
    {
        Pointer = LeftController.GetComponent<Test_LaserPointer>();
        LeftSt = LeftController.GetComponent<SteamVR_TrackedController>();
        // 利用Laserpoint里面的事件函數(shù)來檢測(cè)目標(biāo)位置
        Pointer.PointerIn += LeftPointIn;
        //  利用Laserpoint里面的事件函數(shù)來檢測(cè)目標(biāo)位置
        Pointer.PointerOut += LeftPointOut;
        // 利用手柄控制器來檢測(cè)我們的扳機(jī)事件
        LeftSt.TriggerClicked += TriggerClicked;
    }

    // 沒有檢測(cè)到碰撞信息
    void LeftPointOut(object sender, PointerEventArgs e)
    {   // 當(dāng)前位置沒有
        currentTransform = null;
    }
    // 檢測(cè)到碰撞信息
    void LeftPointIn(object sender, PointerEventArgs e)
    {   // 設(shè)置目標(biāo)位置為檢測(cè)到的目標(biāo)
        currentTransform = e.target;
    }
    // 扳機(jī)事件
    void TriggerClicked(object sender, ClickedEventArgs e)
    {
        // 如果檢測(cè)到目標(biāo)位置
        if (currentTransform != null)
        {    // 移動(dòng)
            this.gameObject.transform.position = new Vector3(Pointer.HitPoint.x - LeftController.transform.localPosition.x, Pointer.HitPoint.y, Pointer.HitPoint.z - LeftController.transform.localPosition.z);
        }
    }
}

三、結(jié)果實(shí)現(xiàn)##

掛載腳本,實(shí)現(xiàn)結(jié)果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容