您的位置:首页 > 移动开发 > Unity3D

VRTK插件详解二:交互之事件与委托分析

2017-03-24 16:33 423 查看
1、我们先来将SteamVR_Unity_Toolkit.unitypackage这个包导入,Asset Store里免费下载

2、当Unity熟练到一定程度,事件与委托是必备的基础!所以本文默认我们已经走过基础阶段。交互设计的精华也在于事件与委托的巧妙设计与实现。VR里的交互更不例外

这篇博客,从SteamVR_Unity_Toolkit的代码里剖析下,它是怎么封装SteamVR的事件的。

3、看类VRTK_ControllerEvents.cs

namespace VRTK{    using UnityEngine;    using System.Collections;
public struct ControllerInteractionEventArgs { public uint controllerIndex; public float buttonPressure; public Vector2 touchpadAxis; public float touchpadAngle; }
public delegate void ControllerInteractionEventHandler(object sender, ControllerInteractionEventArgs e);
public class VRTK_ControllerEvents : MonoBehaviour { public enum ButtonAlias { Trigger, Grip, Touchpad_Touch, Touchpad_Press, Application_Menu }
public ButtonAlias pointerToggleButton = ButtonAlias.Grip; public ButtonAlias grabToggleButton = ButtonAlias.Trigger; public ButtonAlias useToggleButton = ButtonAlias.Trigger; public ButtonAlias menuToggleButton = ButtonAlias.Application_Menu;
public int axisFidelity = 1;
public bool triggerPressed = false; public bool triggerAxisChanged = false; public bool applicationMenuPressed = false; public bool touchpadPressed = false; public bool touchpadTouched = false; public bool touchpadAxisChanged = false; public bool gripPressed = false;
public bool pointerPressed = false; public bool grabPressed = false; public bool usePressed = false; public bool menuPressed = false;
public event ControllerInteractionEventHandler TriggerPressed; public event ControllerInteractionEventHandler TriggerReleased;
public event ControllerInteractionEventHandler TriggerAxisChanged;
public event ControllerInteractionEventHandler ApplicationMenuPressed; public event ControllerInteractionEventHandler ApplicationMenuReleased;
public event ControllerInteractionEventHandler GripPressed; public event ControllerInteractionEventHandler GripReleased;
public event ControllerInteractionEventHandler TouchpadPressed; public event ControllerInteractionEventHandler TouchpadReleased;
public event ControllerInteractionEventHandler TouchpadTouchStart; public event ControllerInteractionEventHandler TouchpadTouchEnd;
public event ControllerInteractionEventHandler TouchpadAxisChanged;
public event ControllerInteractionEventHandler AliasPointerOn; public event ControllerInteractionEventHandler AliasPointerOff;
public event ControllerInteractionEventHandler AliasGrabOn; public event ControllerInteractionEventHandler AliasGrabOff;
public event ControllerInteractionEventHandler AliasUseOn; public event ControllerInteractionEventHandler AliasUseOff;
public event ControllerInteractionEventHandler AliasMenuOn; public event ControllerInteractionEventHandler AliasMenuOff;
private uint controllerIndex; private SteamVR_TrackedObject trackedController; private SteamVR_Controller.Device device;
private Vector2 touchpadAxis = Vector2.zero; private Vector2 triggerAxis = Vector2.zero;
public virtual void OnTriggerPressed(ControllerInteractionEventArgs e) { if (TriggerPressed != null) TriggerPressed(this, e); }
public virtual void OnTriggerReleased(ControllerInteractionEventArgs e) { if (TriggerReleased != null) TriggerReleased(this, e); }
public virtual void OnTriggerAxisChanged(ControllerInteractionEventArgs e) { if (TriggerAxisChanged != null) TriggerAxisChanged(this, e); }
public virtual void OnApplicationMenuPressed(ControllerInteractionEventArgs e) { if (ApplicationMenuPressed != null) ApplicationMenuPressed(this, e); }
public virtual void OnApplicationMenuReleased(ControllerInteractionEventArgs e) { if (ApplicationMenuReleased != null) ApplicationMenuReleased(this, e); }
public virtual void OnGripPressed(ControllerInteractionEventArgs e) { if (GripPressed != null) GripPressed(this, e); }
public virtual void OnGripReleased(ControllerInteractionEventArgs e) { if (GripReleased != null) GripReleased(this, e); }
public virtual void OnTouchpadPressed(ControllerInteractionEventArgs e) { if (TouchpadPressed != null) TouchpadPressed(this, e); }
public virtual void OnTouchpadReleased(ControllerInteractionEventArgs e) { if (TouchpadReleased != null) TouchpadReleased(this, e); }
public virtual void OnTouchpadTouchStart(ControllerInteractionEventArgs e) { if (TouchpadTouchStart != null) TouchpadTouchStart(this, e); }
public virtual void OnTouchpadTouchEnd(ControllerInteractionEventArgs e) { if (TouchpadTouchEnd != null) TouchpadTouchEnd(this, e); }
public virtual void OnTouchpadAxisChanged(ControllerInteractionEventArgs e) { if (TouchpadAxisChanged != null) TouchpadAxisChanged(this, e); }
public virtual void OnAliasPointerOn(ControllerInteractionEventArgs e) { if (AliasPointerOn != null) AliasPointerOn(this, e); }
public virtual void OnAliasPointerOff(ControllerInteractionEventArgs e) { if (AliasPointerOff != null) AliasPointerOff(this, e); }
public virtual void OnAliasGrabOn(ControllerInteractionEventArgs e) { if (AliasGrabOn != null) AliasGrabOn(this, e); }
public virtual void OnAliasGrabOff(ControllerInteractionEventArgs e) { if (AliasGrabOff != null) AliasGrabOff(this, e); }
public virtual void OnAliasUseOn(ControllerInteractionEventArgs e) { if (AliasUseOn != null) AliasUseOn(this, e); }
public virtual void OnAliasUseOff(ControllerInteractionEventArgs e) { if (AliasUseOff != null) AliasUseOff(this, e); }
public virtual void OnAliasMenuOn(ControllerInteractionEventArgs e) { if (AliasMenuOn != null) AliasMenuOn(this, e); }
public virtual void OnAliasMenuOff(ControllerInteractionEventArgs e) { if (AliasMenuOff != null) AliasMenuOff(this, e); }
ControllerInteractionEventArgs SetButtonEvent(ref bool buttonBool, bool value, float buttonPressure) { buttonBool = value; ControllerInteractionEventArgs e; e.controllerIndex = controllerIndex; e.buttonPressure = buttonPressure; e.touchpadAxis = device.GetAxis();
float angle = Mathf.Atan2(e.touchpadAxis.y, e.touchpadAxis.x) * Mathf.Rad2Deg; angle = 90.0f - angle; if (angle < 0) angle += 360.0f;
e.touchpadAngle = angle;
return e; }
void Awake() { trackedController = GetComponent<SteamVR_TrackedObject>(); }
void Start() { controllerIndex = (uint)trackedController.index; device = SteamVR_Controller.Input((int)controllerIndex); }
void EmitAlias(ButtonAlias type, bool touchDown, float buttonPressure, ref bool buttonBool) { if (pointerToggleButton == type) { if (touchDown) { pointerPressed = true; OnAliasPointerOn(SetButtonEvent(ref buttonBool, true, buttonPressure)); } else { pointerPressed = false; OnAliasPointerOff(SetButtonEvent(ref buttonBool, false, buttonPressure)); } }
if (grabToggleButton == type) { if (touchDown) { grabPressed = true; OnAliasGrabOn(SetButtonEvent(ref buttonBool, true, buttonPressure)); } else { grabPressed = false; OnAliasGrabOff(SetButtonEvent(ref buttonBool, false, buttonPressure)); } }
if (useToggleButton == type) { if (touchDown) { usePressed = true; OnAliasUseOn(SetButtonEvent(ref buttonBool, true, buttonPressure)); } else { usePressed = false; OnAliasUseOff(SetButtonEvent(ref buttonBool, false, buttonPressure)); } }
if (menuToggleButton == type) { if (touchDown) { menuPressed = true; OnAliasMenuOn(SetButtonEvent(ref buttonBool, true, buttonPressure)); } else { menuPressed = false; OnAliasMenuOff(SetButtonEvent(ref buttonBool, false, buttonPressure)); } } }
bool Vector2ShallowEquals(Vector2 vectorA, Vector2 vectorB) { return (vectorA.x.ToString("F" + axisFidelity) == vectorB.x.ToString("F" + axisFidelity) && vectorA.y.ToString("F" + axisFidelity) == vectorB.y.ToString("F" + axisFidelity)); }
void Update() { controllerIndex = (uint)trackedController.index; device = SteamVR_Controller.Input((int)controllerIndex);
Vector2 currentTriggerAxis = device.GetAxis(Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger); Vector2 currentTouchpadAxis = device.GetAxis();
if (Vector2ShallowEquals(triggerAxis, currentTriggerAxis)) { triggerAxisChanged = false; } else { OnTriggerAxisChanged(SetButtonEvent(ref triggerAxisChanged, true, currentTriggerAxis.x)); }
if (Vector2ShallowEquals(touchpadAxis, currentTouchpadAxis)) { touchpadAxisChanged = false; } else { OnTouchpadAxisChanged(SetButtonEvent(ref touchpadTouched, true, 1f)); touchpadAxisChanged = true; }
touchpadAxis = new Vector2(currentTouchpadAxis.x, currentTouchpadAxis.y); triggerAxis = new Vector2(currentTriggerAxis.x, currentTriggerAxis.y);
//Trigger if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Trigger)) { OnTriggerPressed(SetButtonEvent(ref triggerPressed, true, currentTriggerAxis.x)); EmitAlias(ButtonAlias.Trigger, true, currentTriggerAxis.x, ref triggerPressed); } else if (device.GetTouchUp(SteamVR_Controller.ButtonMask.Trigger)) { OnTriggerReleased(SetButtonEvent(ref triggerPressed, false, 0f)); EmitAlias(ButtonAlias.Trigger, false, 0f, ref triggerPressed); }
//ApplicationMenu if (device.GetTouchDown(SteamVR_Controller.ButtonMask.ApplicationMenu)) { OnApplicationMenuPressed(SetButtonEvent(ref applicationMenuPressed, true, 1f)); EmitAlias(ButtonAlias.Application_Menu, true, 1f, ref applicationMenuPressed); } else if (device.GetTouchUp(SteamVR_Controller.ButtonMask.ApplicationMenu)) {
OnApplicationMenuReleased(SetButtonEvent(ref applicationMenuPressed, false, 0f)); EmitAlias(ButtonAlias.Application_Menu, false, 0f, ref applicationMenuPressed); }
//Grip if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Grip)) { OnGripPressed(SetButtonEvent(ref gripPressed, true, 1f)); EmitAlias(ButtonAlias.Grip, true, 1f, ref gripPressed); } else if (device.GetTouchUp(SteamVR_Controller.ButtonMask.Grip)) { OnGripReleased(SetButtonEvent(ref gripPressed, false, 0f)); EmitAlias(ButtonAlias.Grip, false, 0f, ref gripPressed); }
//Touchpad Pressed if (device.GetPressDown(SteamVR_Controller.ButtonMask.Touchpad)) { OnTouchpadPressed(SetButtonEvent(ref touchpadPressed, true, 1f)); EmitAlias(ButtonAlias.Touchpad_Press, true, 1f, ref touchpadPressed); } else if (device.GetPressUp(SteamVR_Controller.ButtonMask.Touchpad)) { OnTouchpadReleased(SetButtonEvent(ref touchpadPressed, false, 0f)); EmitAlias(ButtonAlias.Touchpad_Press, false, 0f, ref touchpadPressed); }
//Touchpad Touched if (device.GetTouchDown(SteamVR_Controller.ButtonMask.Touchpad)) { OnTouchpadTouchStart(SetButtonEvent(ref touchpadTouched, true, 1f)); EmitAlias(ButtonAlias.Touchpad_Touch, true, 1f, ref touchpadTouched); } else if (device.GetTouchUp(SteamVR_Controller.ButtonMask.Touchpad)) { OnTouchpadTouchEnd(SetButtonEvent(ref touchpadTouched, false, 0f)); EmitAlias(ButtonAlias.Touchpad_Touch, false, 0f, ref touchpadTouched); } } }}

  在这个类中我们可以看到,枚举类ButtonAlias里的元素,分别对应HTCVive控制柄上的按钮:

Trigger:能扣动的那个按钮;

Grip:控制柄侧面的两个按钮;

Touchpad_Touch:触摸板的触控;

Touchpad_Press:触摸板的按压;

Application_Menu:触摸板上方的小按钮,触摸板下方的按钮是统一的总菜单功能键,不能自定义开发,所以没有与它对应的名称。(这句是我的理解,但没有试验过,如果哪位试过,望告知...)

ControllerInteractionEventHandler类型的委托方法有:

TriggerPressed——扳机按下;

TriggerReleased——扳机放开;

TriggerAxisChanged——扳机轴值的改变;

ApplicationMenuPressed——ApplicationMenu按钮按下;

ApplicationMenuReleased——ApplicationMenu按钮放开;

GripPressed——Grip按钮按下;

GripReleased——Grip按钮放开;

TouchpadPressed——触摸板按钮按下;

TouchpadReleased——触摸板按钮放开;

TouchpadTouchStart——触摸板开始触摸;

TouchpadTouchEnd——触摸板结束触摸;

TouchpadAxisChanged——触摸板触摸时的轴值变化;

AliasPointerOn;

AliasPointerOff;

AliasGrabOn;

AliasGrabOff;

AliasUseOn;

AliasUseOff;

AliasMenuOn;

AliasMenuOff;

接下来,我们来看下,Toolkit具体是怎么自己封装的SteamVR控制柄的事件的。

  在VRTK_ControllerEvents.cs这个脚本的Update()中,我们先找到这样一段代码:



  从这段代码中(代码的意思很简单,我就不说了,具体看下它的逻辑处理),我们可以看到,每帧监听一次SteamVR中的控制柄状态,当监听到状态后,执行一次自己的委托事件(ControllerInteractionEventHandler),并且执行一次EmitAlias(ButtonAlias type, bool touchDown, float buttonPressure, ref bool buttonBool)方法。EmitAlias方法是用来判断并分发事件给AliasXX(oN/oFF)的(就是刚才分割线以下的那些委托方法)。

  至于AliasXX(oN/oFF)这些委托方法怎么用?我们可以先看下这个VRTK_ControllerEvents.cs挂接脚本在Inspector面板中的序列化属性:



  AliasXX(oN/oFF)委托方法对应:


  至于Inspector面板中的其它属性,都没有实际用处,不需要我们去自定义,所以如果不想看到的话,可以自己在脚本中的相应变量上加上[HideInInspector],最后:



  Tollkit对SteamVR的封装逻辑很简单,用这么长的篇幅来说,主要目的还是想自己再仔细研究下,虽然它的逻辑简单,但是我觉的它的代码结构很漂亮。不感兴趣的,可以忽略。至于怎么用,Toolkit也给出了一个挂接脚本,很简单的用法,我挂一下它的代码就行,看完很容易理解:

   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
using UnityEngine;using System.Collections;using VRTK;
public class VRTK_ControllerEvents_ListenerExample : MonoBehaviour {
// Use this for initialization void Start () { if (GetComponent<VRTK_ControllerEvents>() == null) { Debug.LogError("VRTK_ControllerEvents_ListenerExample is required to be attached to a SteamVR Controller that has the VRTK_ControllerEvents script attached to it"); return; } //Setup controller event listeners GetComponent<VRTK_ControllerEvents>().TriggerPressed += new ControllerInteractionEventHandler(DoTriggerPressed); GetComponent<VRTK_ControllerEvents>().TriggerReleased += new ControllerInteractionEventHandler(DoTriggerReleased);
GetComponent<VRTK_ControllerEvents>().TriggerAxisChanged += new ControllerInteractionEventHandler(DoTriggerAxisChanged);
GetComponent<VRTK_ControllerEvents>().ApplicationMenuPressed += new ControllerInteractionEventHandler(DoApplicationMenuPressed); GetComponent<VRTK_ControllerEvents>().ApplicationMenuReleased += new ControllerInteractionEventHandler(DoApplicationMenuReleased);
GetComponent<VRTK_ControllerEvents>().GripPressed += new ControllerInteractionEventHandler(DoGripPressed); GetComponent<VRTK_ControllerEvents>().GripReleased += new ControllerInteractionEventHandler(DoGripReleased);
GetComponent<VRTK_ControllerEvents>().TouchpadPressed += new ControllerInteractionEventHandler(DoTouchpadPressed); GetComponent<VRTK_ControllerEvents>().TouchpadReleased += new ControllerInteractionEventHandler(DoTouchpadReleased);
GetComponent<VRTK_ControllerEvents>().TouchpadTouchStart += new ControllerInteractionEventHandler(DoTouchpadTouchStart); GetComponent<VRTK_ControllerEvents>().TouchpadTouchEnd += new ControllerInteractionEventHandler(DoTouchpadTouchEnd);
GetComponent<VRTK_ControllerEvents>().TouchpadAxisChanged += new ControllerInteractionEventHandler(DoTouchpadAxisChanged); }
void DebugLogger(uint index, string button, string action, ControllerInteractionEventArgs e) { Debug.Log("Controller on index '" + index + "' " + button + " has been " + action + " with a pressure of " + e.buttonPressure + " / trackpad axis at: " + e.touchpadAxis + " (" + e.touchpadAngle + " degrees)"); }
void DoTriggerPressed(object sender, ControllerInteractionEventArgs e) { DebugLogger(e.controllerIndex, "TRIGGER", "pressed down", e); }
void DoTriggerReleased(object sender, ControllerInteractionEventArgs e) { DebugLogger(e.controllerIndex, "TRIGGER", "released", e); }
void DoTriggerAxisChanged(object sender, ControllerInteractionEventArgs e) { DebugLogger(e.controllerIndex, "TRIGGER", "axis changed", e); }
void DoApplicationMenuPressed(object sender, ControllerInteractionEventArgs e) { DebugLogger(e.controllerIndex, "APPLICATION MENU", "pressed down", e); }
void DoApplicationMenuReleased(object sender, ControllerInteractionEventArgs e) { DebugLogger(e.controllerIndex, "APPLICATION MENU", "released", e); }
void DoGripPressed(object sender, ControllerInteractionEventArgs e) { DebugLogger(e.controllerIndex, "GRIP", "pressed down", e); }
void DoGripReleased(object sender, ControllerInteractionEventArgs e) { DebugLogger(e.controllerIndex, "GRIP", "released", e); }
void DoTouchpadPressed(object sender, ControllerInteractionEventArgs e) { DebugLogger(e.controllerIndex, "TOUCHPAD", "pressed down", e); }
void DoTouchpadReleased(object sender, ControllerInteractionEventArgs e) { DebugLogger(e.controllerIndex, "TOUCHPAD", "released", e); }
void DoTouchpadTouchStart(object sender, ControllerInteractionEventArgs e) { DebugLogger(e.controllerIndex, "TOUCHPAD", "touched", e); }
void DoTouchpadTouchEnd(object sender, ControllerInteractionEventArgs e) { DebugLogger(e.controllerIndex, "TOUCHPAD", "untouched", e); }
void DoTouchpadAxisChanged(object sender, ControllerInteractionEventArgs e) { DebugLogger(e.controllerIndex, "TOUCHPAD", "axis changed", e); }}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  streamVR unity3d htc 插件