【Unity XR Input 获取Quest和Pico各个按键状态,按下、抬起、按下中】

Unity XR Input 获取Quest和Pico各个按键状态,按下、抬起、按下中

测试使用的是Unity2021.3.8和Quest2,只需绑定事件即可获取Quest各个按键状态,按下,抬起,按下中··

参考文档:
https://docs.unity3d.com/cn/current/Manual/xr_input.html
https://blog.csdn.net/Q540670228/article/details/123139150

使用以上代码时碰到些小问题(调试时获取不到设备,按钮冲突),部分内容做了修改

实现效果
在这里插入图片描述

全部代码
MonoSingleton.cs

using UnityEngine;

namespace Common
{
    
    
    ///<summary>
    ///脚本单例类,负责为唯一脚本创建实例
    ///<summary>
    public class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T> //注意此约束为T必须为其本身或子类
    {
    
    
        /*
        相较于直接在需要唯一创建的脚本中创建实例,Awake初始化的过程需要解决的问题
        1.代码重复
        2.在Awake里面初始化,其它脚本在Awake中调用其可能会为Null的异常情况
         */

        //解决1:使用泛型创建实例   解决2:使用按需加载(即有其它脚本调用时在get中加载)

        private static T instance; //创建私有对象记录取值,可只赋值一次避免多次赋值

        public static T Instance
        {
    
    
            //实现按需加载
            get
            {
    
    
                //当已经赋值,则直接返回即可
                if (instance != null) return instance;

                instance = FindObjectOfType<T>();

                //为了防止脚本还未挂到物体上,找不到的异常情况,可以自行创建空物体挂上去
                if (instance == null)
                {
    
    
                    //如果创建对象,则会在创建时调用其身上脚本的Awake即调用T的Awake(T的Awake实际上是继承的父类的)
                    //所以此时无需为instance赋值,其会在Awake中赋值,自然也会初始化所以无需init()
                    /*instance = */
                    new GameObject("Singleton of " + typeof(T)).AddComponent<T>();
                }

                return instance;

            }
        }

        private void Awake()
        {
    
    
            //若无其它脚本在Awake中调用此实例,则可在Awake中自行初始化instance
            instance = this as T;
            //初始化
            //Init();
        }
    }
}

InputEvent.cs
//示例中此代码放到了XR Origin上面

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
/// <summary>
/// 提供各种输入事件
/// </summary>
public class InputEvent : Common.MonoSingleton<InputEvent>
{
    
    
    //*************输入设别**************************
    InputDevice leftHandController;
    InputDevice rightHandController;
    InputDevice headController;

    //**************对外提供公开事件******************
    #region public event

    public Action onLeftTriggerEnter;
    public Action onLeftTriggerDown;
    public Action onLeftTriggerUp;

    public Action onRightTriggerEnter;
    public Action onRightTriggerDown;
    public Action onRightTriggerUp;

    public Action onLeftGripEnter;
    public Action onLeftGripDown;
    public Action onLeftGripUp;

    public Action onRightGripEnter;
    public Action onRightGripDown;
    public Action onRightGripUp;

    public Action onLeftAppButtonEnter;
    public Action onLeftAppButtonDown;
    public Action onLeftAppButtonUp;

    public Action onRightAppButtonEnter;
    public Action onRightAppButtonDown;
    public Action onRightAppButtonUp;

    public Action onLeftJoyStickEnter;
    public Action onLeftJoyStickDown;
    public Action onLeftJoyStickUp;

    public Action onRightJoyStickEnter;
    public Action onRightJoyStickDown;
    public Action onRightJoyStickUp;

    public Action<Vector2> onLeftJoyStickMove;
    public Action<Vector2> onRightJoyStickMove;

    public Action onLeftAXButtonEnter;
    public Action onLeftAXButtonDown;
    public Action onLeftAXButtonUp;

    public Action onLeftBYButtonEnter;
    public Action onLeftBYButtonDown;
    public Action onLeftBYButonUp;

    public Action onRightAXButtonEnter;
    public Action onRightAXButtonDown;
    public Action onRightAXButtonUp;

    public Action onRightBYButtonEnter;
    public Action onRightBYButtonDown;
    public Action onRightBYButtonUp;

    #endregion

    //提供状态字典独立记录各个feature的状态
    Dictionary<string, bool> stateDic;

    private void Init()
    {
    
    
        if (!leftHandController.isValid)
        {
    
    
            leftHandController = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand);
        }
        if (!rightHandController.isValid)
        {
    
    
            rightHandController = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
        }
        if (!headController.isValid)
        {
    
    
            headController = InputDevices.GetDeviceAtXRNode(XRNode.Head);
        }
        stateDic = new Dictionary<string, bool>();

    }

    //*******************事件源的触发**************************
    /// <summary>
    /// 按钮事件源触发模板
    /// </summary>
    /// <param name="device">设备</param>
    /// <param name="usage">功能特征</param>
    /// <param name="btnEnter">开始按下按钮事件</param>
    /// <param name="btnDown">按下按钮事件</param>
    /// <param name="btnUp">抬起按钮事件</param>
    private void ButtonDispatchModel(InputDevice device, InputFeatureUsage<bool> usage, Action btnEnter, Action btnDown, Action btnUp)
    {
    
    
        //Debug.Log("usage:" + usage.name);
        //为首次执行的feature添加bool状态 -- 用以判断Enter和Up状态
        string featureKey = device.characteristics + usage.name;
        if (!stateDic.ContainsKey(featureKey))
        {
    
    
            stateDic.Add(featureKey, false);
        }

        bool isDown;
        if (device.TryGetFeatureValue(usage, out isDown) && isDown)
        {
    
    
            //Debug.Log("device:" + device.characteristics + "usage:" + usage.name);
            if (!stateDic[featureKey])
            {
    
    
                stateDic[featureKey] = true;
                btnEnter?.Invoke();
            }
            btnDown?.Invoke();
        }
        else
        {
    
    
            if (stateDic[featureKey])
            {
    
    
                btnUp?.Invoke();
                stateDic[featureKey] = false;
            }
        }
    }

    /// <summary>
    /// 摇杆事件源触发模板
    /// </summary>
    /// <param name="device">设备</param>
    /// <param name="usage">功能特征</param>
    /// <param name="joyStickMove">移动摇杆事件</param>
    private void JoyStickDispatchModel(InputDevice device, InputFeatureUsage<Vector2> usage, Action<Vector2> joyStickMove)
    {
    
    
        Vector2 axis;
        if (device.TryGetFeatureValue(usage, out axis) && !axis.Equals(Vector2.zero))
        {
    
    
            if (joyStickMove != null)
                joyStickMove(axis);
        }
    }

    //******************每帧轮询监听事件***********************
    private void Update()
    {
    
    
        if (leftHandController.isValid)
        {
    
    
            ButtonDispatchModel(leftHandController, CommonUsages.triggerButton, onLeftTriggerEnter, onLeftTriggerDown, onLeftTriggerUp);
            ButtonDispatchModel(leftHandController, CommonUsages.gripButton, onLeftGripEnter, onLeftGripDown, onLeftGripUp);
            ButtonDispatchModel(leftHandController, CommonUsages.primaryButton, onLeftAXButtonEnter, onLeftAXButtonDown, onLeftAXButtonUp);
            ButtonDispatchModel(leftHandController, CommonUsages.secondaryButton, onLeftBYButtonEnter, onLeftBYButtonDown, onLeftBYButonUp);
            ButtonDispatchModel(leftHandController, CommonUsages.primary2DAxisClick, onLeftJoyStickEnter, onLeftJoyStickDown, onLeftJoyStickUp);
            ButtonDispatchModel(leftHandController, CommonUsages.menuButton, onLeftAppButtonEnter, onLeftAppButtonDown, onLeftAppButtonUp);
            //JoyStickDispatchModel(leftHandController, CommonUsages.primary2DAxis, onLeftJoyStickMove);
        }
        else
        {
    
    
            Init();
        }
        if (rightHandController.isValid)
        {
    
    
            ButtonDispatchModel(rightHandController, CommonUsages.triggerButton, onRightTriggerEnter, onRightTriggerDown, onRightTriggerUp);
            ButtonDispatchModel(rightHandController, CommonUsages.gripButton, onRightGripEnter, onRightGripDown, onRightGripUp);
            ButtonDispatchModel(rightHandController, CommonUsages.primaryButton, onRightAXButtonEnter, onRightAXButtonDown, onRightAXButtonUp);
            ButtonDispatchModel(rightHandController, CommonUsages.secondaryButton, onRightBYButtonEnter, onRightBYButtonDown, onRightBYButtonUp);
            ButtonDispatchModel(rightHandController, CommonUsages.primary2DAxisClick, onRightJoyStickEnter, onRightJoyStickDown, onRightJoyStickUp);
            ButtonDispatchModel(rightHandController, CommonUsages.menuButton, onRightAppButtonEnter, onRightAppButtonDown, onRightAppButtonUp);
            //JoyStickDispatchModel(rightHandController, CommonUsages.primary2DAxis, onRightJoyStickMove);
        }
        else
        {
    
    
            Init();
        }
    }
}

使用示例
LeftHandButton.cs
//示例中此代码放到了LeftHand Controller上面

using UnityEngine;

public class LeftHandButton : MonoBehaviour
{
    
    
    private void Awake()
    {
    
    
        InputEvent.Instance.onLeftAXButtonUp += LeftAXButtonUp;
        InputEvent.Instance.onLeftAXButtonEnter += LeftAXButtonEnter;
        InputEvent.Instance.onLeftAXButtonDown += LeftAXButtonDown;
    }
    void LeftAXButtonDown()
    {
    
    
        print("左手柄A键按下中···");
    }
    void LeftAXButtonEnter()
    {
    
    
        print("按下左手柄A键");
    }
    void LeftAXButtonUp()
    {
    
    
        print("抬起左手柄A键");
    }
}

猜你喜欢

转载自blog.csdn.net/w291720094/article/details/127104696