前言:
玩 VR 游戏时发现 Touch Pad 上下左右分别按下开启不同的功能的体验还真不错。
目前为止好像 VRTK 4.0 还没有整理这个上下左右按下的事件?
算了,考虑人家有没有整的空挡,都够自己整一个了,如下:
代码
using System;
using System.Linq;
using Tilia.Input.UnityInputManager;
using UnityEngine;
using UnityEngine.Events;
public enum TouchPadDirection
{
Up = 0,
Bottom = 2,
Left = 1,
Right = 3,
None = 4,
}
/// <summary>
/// 脚本用于判断你按下HTC vive TouchPad(上下左右)的哪一个区域了
/// </summary>
public class TouchPadClickEventDispatcher : MonoBehaviour
{
[Header("Touch Pad 点击事件")]
public TouchPadClickEvent OnTouchPadClicked = new TouchPadClickEvent();
private void Start()
{
buttonAction.Activated.AddListener(OnButtonActionActived);
//当按键抬起时报告 None
buttonAction.Deactivated.AddListener(v=>OnTouchPadClicked.Invoke( TouchPadDirection.None));
}
private void OnButtonActionActived(bool arg0)
{
var angle = Vector2.SignedAngle(new Vector2(1, 1), new Vector2(hr.Value, vt.Value));
//带符号角度转换为 0°~360°
angle += angle < 0 ? 360 : 0;
//每 90° 的刻度划分一个方向,逆时针进行
var dir = (TouchPadDirection)Mathf.FloorToInt(angle / 90);
OnTouchPadClicked.Invoke(dir);
}
private void Reset()
{
var bts = GetComponentsInChildren<UnityInputManagerButtonAction>();
var _1ds = GetComponentsInChildren<UnityInputManagerAxis1DAction>();
buttonAction = bts.FirstOrDefault(v => v.name.Contains("Trackpad_Press"));
hr = _1ds.FirstOrDefault(v => v.name.Contains("Trackpad_HorizontalAxis"));
vt = _1ds.FirstOrDefault(v => v.name.Contains("Trackpad_VerticalAxis"));
if (!buttonAction || !hr || !vt)
{
Debug.LogError("TouchPadClickEventDispatcher 挂载失败 \n 请挂载在 Input.UnityInputManager.OpenVR.RightController 或者 Input.UnityInputManager.OpenVR.LeftController");
DestroyImmediate(this);
}
else
{
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(this);
#endif
}
}
[SerializeField, HideInInspector]
UnityInputManagerButtonAction buttonAction;
[SerializeField, HideInInspector]
UnityInputManagerAxis1DAction hr;
[SerializeField, HideInInspector]
UnityInputManagerAxis1DAction vt;
[Serializable]
public class TouchPadClickEvent : UnityEvent<TouchPadDirection> { }
}
- 实现了 TouchPad上下左右按下时输出事件进行区分。
- 实现了防呆操作,只有在 手柄控制器 上的挂载行为才被许可。
- 实现自动获取所需组件的引用并序列化。
以下为测试事件的代码,挂载在场景任意空物体中,赋值即可测试使用
using UnityEngine;
public class TouchPadClickEventReceiver : MonoBehaviour
{
[SerializeField]
TouchPadClickEventDispatcher dispatcher;
private void Start() => dispatcher.OnTouchPadClicked.AddListener(OnTouchPadClicked);
private void OnTouchPadClicked(TouchPadDirection arg0)
{
switch (arg0)
{
case TouchPadDirection.Up:
Debug.Log($"{nameof(TouchPadClickEventReceiver)}: 上 ");
break;
case TouchPadDirection.Bottom:
Debug.Log($"{nameof(TouchPadClickEventReceiver)}: 下 ");
break;
case TouchPadDirection.Right:
Debug.Log($"{nameof(TouchPadClickEventReceiver)}: 右 ");
break;
case TouchPadDirection.Left:
Debug.Log($"{nameof(TouchPadClickEventReceiver)}: 左 ");
break;
default:
Debug.Log($"{nameof(TouchPadClickEventReceiver)}: TouchPad 按钮松开了");
break;
}
}
}
结语
- 通过本例可以学到不少小细节:方法体表达式呀,Linq呀,SerializeField 和 HideInInspector 属性的组合使用呀,OnReset 方法的使用呀
- 开箱即食,欢迎品尝。