SteamVR 手柄交互
为了在 Unity 中与 SteamVR 交互,可下载并引入 SteamVR 插件。安装并加载完成后,可在 Window -> SteamVR Input 中设置输入系统。在输入系统中,VR 设备的输入需要和动作绑定,一个动作集合可以包含多个动作。以示例项目中的 platformer 动作集合为例:

platformer 动作集合包含两个输入动作:Move 动作的类型为 Vector 2,表示输入动作将会返回二维向量,比如说操控杆的位置或者手指在触控板上的位置;而 Jump 动作的类型为 Boolean,表示输入的动作只有两种状态,比如说某个按键是否被点击。


为了演示更多动作,此处再加入一个 Boolean 类型的动作 Disappear:

设置完成后,点击 Opening binding UI,在设置页面中将动作与输入设备绑定。该设定是与具体的 VR 设备相关的,对于 HTC Vive 来说,手柄的握持键、菜单按钮、骨骼、扳机键、触控板和系统按钮皆可接收输入行为。在 platformer 动作集合中,进行如下设置:
-
将
握持键的点击事件与Disappear动作关联,该输入动作属于布尔类型,表示握持键是否被按下。 -
将
触控板的点击事件与Jump动作关联,该输入动作属于布尔类型,表示触控板是否被点击。 -
将
触控板的位置信息与Move动作关联,该输入动作属于二维向量类型,表示触控板被触摸的位置。

完成以上的设置后,可将 platformer 动作集合用于具体的场景中。
以交互系统示例中的远程遥控场景为例:现在有一个玩偶预制 JoeJeff,具有移动、跳跃和消失等行为,玩家可通过遥控器 JoeJeffController 来操控该玩偶。
首先需要为遥控器预制绑定 Interactable 脚本(由插件提供),用于探测手柄对该物体的抓取事件。然后,在与遥控器预制绑定的 JoeJeffController 脚本中获取 Interactable,用于获取抓取的相关数据:
private Interactable interactable;
输入系统中设置的三个动作可通过 SteamVR_Input.GetAction 函数获取:
public SteamVR_Action_Vector2 moveAction = SteamVR_Input.GetAction<SteamVR_Action_Vector2>("platformer", "Move");
public SteamVR_Action_Boolean jumpAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("platformer", "Jump");
public SteamVR_Action_Boolean disappearAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("platformer", "Disappear");
这三个动作可以用三个变量表示:
private Vector3 movement;
private bool jump;
private bool disappear;
为了获取输入源的类型(左手柄或右右手柄),可定义一个 SteamVR_Input_Sources 类型(其实就是一个枚举类型)的变量 hand:
private SteamVR_Input_Sources hand;
在遥控器中引用玩偶变量:
public JoeJeff character;
通过 interactable.attachedToHand 变量即可确定遥控器是否被玩家(手柄)抓住。如果是的话,在通过 interactable.attachedToHand.handType 判断抓取该物体的是左手柄还是右手柄。之后,通过 moveAction[hand].axis 可获得玩家的手指在触控板上的位置,作为玩偶移动方向的依据;通过 jumpAction[hand].stateDown 可判断玩家是否按下了触控板,作为玩偶是否跳跃的依据;通过 disappearAction[hand].stateDown 可判断玩家是否按下了握持键,作为让玩偶消失或出现的依据。
private void Update() {
if (interactable.attachedToHand) {
hand = interactable.attachedToHand.handType;
Vector2 m = moveAction[hand].axis;
movement = new Vector3(m.x, 0, m.y);
jump = jumpAction[hand].stateDown;
glow = Mathf.Lerp(glow, jumpAction[hand].state ? 1.5f : 1.0f, Time.deltaTime * 20);
if (disappearAction[hand].stateDown) {
disappear = !disappear;
}
}
else {
movement = Vector2.zero;
jump = false;
glow = 0;
}
Joystick.localPosition = movement * joyMove;
float rot = transform.eulerAngles.y;
movement = Quaternion.AngleAxis(rot, Vector3.up) * movement;
jumpHighlight.sharedMaterial.SetColor("_EmissionColor", Color.white * glow);
if (disappear) {
character.Disappear();
}
else {
character.Appear();
character.Move(movement * 2, jump);
}
}
实际效果
- 按下握持键,玩偶消失。


- 触摸触控板,玩偶移动。

- 点击触控板,玩偶跳跃。
