Unity Gear Vr对象交互

时间:2018-03-08 21:38:31

标签: c# unity3d interaction gear-vr gearvrcontroller

当激光击中物体并且用户按下控制器的后侧按钮时,我想用Gear VR控制器选择场景中的物体。我已经为控制器完成了光线投射和激光,它工作正常,但我找不到让选择工作的方法。代码如下,我也评论了我写的部分以及它应该做的事情。

using System;
using UnityEngine;

namespace VRStandardAssets.Utils
{
    // In order to interact with objects in the scene
    // this class casts a ray into the scene and if it finds
    // a VRInteractiveItem it exposes it for other classes to use.
    // This script should be generally be placed on the camera.
    public class VREyeRaycaster : MonoBehaviour
    {
        public event Action<RaycastHit> OnRaycasthit;                   // This event is called every frame that the user's gaze is over a collider.



        [SerializeField]
        private LineRenderer m_LineRenderer = null; // For supporting Laser Pointer
        public bool ShowLineRenderer = true;                         // Laser pointer visibility
        [SerializeField]
        private Transform m_TrackingSpace = null;   // Tracking space (for line renderer)




        [SerializeField]
        private Transform m_Camera;
        [SerializeField]
        private LayerMask m_ExclusionLayers;           // Layers to exclude from the raycast.
        [SerializeField]
        private Reticle m_Reticle;                     // The reticle, if applicable.
        [SerializeField]
        private VRInput m_VrInput;                     // Used to call input based events on the current VRInteractiveItem.
        [SerializeField]
        private bool m_ShowDebugRay;                   // Optionally show the debug ray.
        [SerializeField]
        private float m_DebugRayLength = 5f;           // Debug ray length.
        [SerializeField]
        private float m_DebugRayDuration = 1f;         // How long the Debug ray will remain visible.
        [SerializeField]
        private float m_RayLength = 500f;              // How far into the scene the ray is cast.


        private VRInteractiveItem m_CurrentInteractible;                //The current interactive item
        private VRInteractiveItem m_LastInteractible;                   //The last interactive item
        private String m_IIName;
        private string[] objArrayName1 = {"Clock","Train", "Chair", "Pant", "Bed", "BlueHat" };
        private string[] objArrayName2 = { "BookOld", "Lambo", "NotebookGRN", "Airplane", "Cup1", "Teddy" };
        private int phase = 0;
        private short i = 0;
        private OVRInput.Controller controller;

        // Utility for other classes to get the current interactive item
        public VRInteractiveItem CurrentInteractible
        {
            get { return m_CurrentInteractible; }
        }


        private void OnEnable()
        {
            m_VrInput.OnClick += HandleClick;
            m_VrInput.OnDoubleClick += HandleDoubleClick;
            m_VrInput.OnUp += HandleUp;
            m_VrInput.OnDown += HandleDown;
        }


        private void OnDisable()
        {
            m_VrInput.OnClick -= HandleClick;
            m_VrInput.OnDoubleClick -= HandleDoubleClick;
            m_VrInput.OnUp -= HandleUp;
            m_VrInput.OnDown -= HandleDown;
        }


        private void Update()
        {
            EyeRaycast();
        }


        private void EyeRaycast()
        {
            // Show the debug ray if required
            if (m_ShowDebugRay)
            {
                Debug.DrawRay(m_Camera.position, m_Camera.forward * m_DebugRayLength, Color.blue, m_DebugRayDuration);
            }

            // Create a ray that points forwards from the camera.
            Ray ray = new Ray(m_Camera.position, m_Camera.forward);
            RaycastHit hit;

            Vector3 worldStartPoint = Vector3.zero;
            Vector3 worldEndPoint = Vector3.zero;
            if (m_LineRenderer != null)
            {
                m_LineRenderer.enabled = ControllerIsConnected && ShowLineRenderer;
            }

            if (ControllerIsConnected && m_TrackingSpace != null)
            {
                Matrix4x4 localToWorld = m_TrackingSpace.localToWorldMatrix;
                Quaternion orientation = OVRInput.GetLocalControllerRotation(Controller);

                Vector3 localStartPoint = OVRInput.GetLocalControllerPosition(Controller);
                Vector3 localEndPoint = localStartPoint + ((orientation * Vector3.forward) * 500.0f);

                worldStartPoint = localToWorld.MultiplyPoint(localStartPoint);
                worldEndPoint = localToWorld.MultiplyPoint(localEndPoint);

                // Create new ray
                ray = new Ray(worldStartPoint, worldEndPoint - worldStartPoint);
            }

            // Do the raycast forweards to see if we hit an interactive item
            if (Physics.Raycast(ray, out hit, m_RayLength, ~m_ExclusionLayers))
            {
                VRInteractiveItem interactible = hit.collider.GetComponent<VRInteractiveItem>(); //attempt to get the VRInteractiveItem on the hit object
                if (interactible)
                {
                    worldEndPoint = hit.point;
                }
                    m_CurrentInteractible = interactible;


                //****************************************************     I started coding here   (If the user selects an interactive object the we have to check if it's in phase A or B of the game     *****************************************************************
                if (OVRInput.Get(OVRInput.Button.PrimaryIndexTrigger))  //If the user pressed the back side button of the controller
                {


                    m_IIName = m_CurrentInteractible.name;                                              
                    if (phase == 0)
                    {
                        while (m_IIName != objArrayName1[i] && i < 6) // Looking through the object name array to see if we have found an interactive object belonging in Phase A
                        {
                            i++;
                        }
                        if (i < 6) // The object belongs in Phase A
                        { //If we have found an interractive item belonging in Phase A then we have to trigger it 
                            Debug.Log("Found an inter item of phase A");
                            m_CurrentInteractible.transform.Rotate(Vector3.right * 10);
                        }
                        else // Did not belong in Phase A
                        {
                            i = 0;
                        }

                    }
                    else
                    {
                        while (m_IIName != objArrayName2[i] && i < 6) // Looking through the object name array to see if we have found an interactive object belonging in Phase B
                        {
                            i++;
                        }
                        if (i < 6) // The object belongs in Phase B
                        { //If we have found an interractive item belonging in Phase B then we have to trigger it 
                            Debug.Log("Found an inter item of phase B");
                        }
                        else
                        {
                            i = 0; // Did not belong in Phase B
                        }

                    }
                }

                    //**************************************************************************     I stoped coding here              ********************************************************************



                // If we hit an interactive item and it's not the same as the last interactive item, then call Over
                if (interactible && interactible != m_LastInteractible)
                    interactible.Over();

                // Deactive the last interactive item 
                if (interactible != m_LastInteractible)
                    DeactiveLastInteractible();

                m_LastInteractible = interactible;

                // Something was hit, set at the hit position.
                if (m_Reticle)
                    m_Reticle.SetPosition(hit);

                if (OnRaycasthit != null)
                    OnRaycasthit(hit);
            }
            else
            {
                // Nothing was hit, deactive the last interactive item.
                DeactiveLastInteractible();
                m_CurrentInteractible = null;

                // Position the reticle at default distance.
                if (m_Reticle)
                    m_Reticle.SetPosition(ray.origin, ray.direction);
            }

            if (ControllerIsConnected && m_LineRenderer != null)
            {
                m_LineRenderer.SetPosition(0, worldStartPoint);
                m_LineRenderer.SetPosition(1, worldEndPoint);
            }
        }

        public bool ControllerIsConnected
        {
            get
            {
                OVRInput.Controller controller = OVRInput.GetConnectedControllers() & (OVRInput.Controller.LTrackedRemote | OVRInput.Controller.RTrackedRemote);
                return controller == OVRInput.Controller.LTrackedRemote || controller == OVRInput.Controller.RTrackedRemote;
            }
        }
        public OVRInput.Controller Controller
        {
            get
            {
                OVRInput.Controller controller = OVRInput.GetConnectedControllers();
                if ((controller & OVRInput.Controller.LTrackedRemote) == OVRInput.Controller.LTrackedRemote)
                {
                    return OVRInput.Controller.LTrackedRemote;
                }
                else if ((controller & OVRInput.Controller.RTrackedRemote) == OVRInput.Controller.RTrackedRemote)
                {
                    return OVRInput.Controller.RTrackedRemote;
                }
                return OVRInput.GetActiveController();
            }
        }


        private void DeactiveLastInteractible()
        {
            if (m_LastInteractible == null)
                return;

            m_LastInteractible.Out();
            m_LastInteractible = null;
        }


        private void HandleUp()
        {
            if (m_CurrentInteractible != null)
                m_CurrentInteractible.Up();
        }


        private void HandleDown()
        {
            if (m_CurrentInteractible != null)
                m_CurrentInteractible.Down();
        }


        private void HandleClick()
        {
            if (m_CurrentInteractible != null)
                m_CurrentInteractible.Click();
        }


        private void HandleDoubleClick()
        {
            if (m_CurrentInteractible != null)
                m_CurrentInteractible.DoubleClick();

        }
    }
}

1 个答案:

答案 0 :(得分:0)

你是VRInteractiveItem订阅了动作OnOver,OnClick等。正在OnCancel中,这个动作被激活到GearVr上的后退按钮。

所以我建议你编写另一个类,比如(让我们假设激光给它的对象是一个CubeObject)对这个交互式对象有一个参考,并将这个类附加到对象上:

namespace VRStandardAssets.Menu
{

    public class CubeObject : MonoBehaviour
    {
        [SerializeField] private VRInteractiveItem m_InteractiveItem;       // The interactive item script reference from the same gameobject.
        [SerializeField] private bool isLookingAtIt = false;            //flag to know if player is onOver the object

        private void OnEnable ()
        {
            m_InteractiveItem.OnOver += HandleOver;
            m_InteractiveItem.OnOut += HandleOut;
            m_InteractiveItem.OnCancel += HandleCancel;
        }    
        private void OnDisable ()
        {
            m_InteractiveItem.OnOver -= HandleOver;
            m_InteractiveItem.OnOut -= HandleOut;
            m_InteractiveItem.OnCancel -= HandleCancel;
        }

         private void HandleCancel()
        {
            //Do stuff when I click on the object
            doBackButtonStuff();
        }

        private void doBackButtonStuff(){
            if(isLookingAtIt){
                print("user has clicked back button while raycast hit it");
            }
        }

        private void HandleOver()
        {
            //Do things when the object is onOver
            isLookingAtIt = true;
        }
         private void HandleOut()
        {
            //Do things when the object is onOut
            isLookingAtIt = false;
        }
    }
}