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);
}
}
实际效果
- 按下握持键,玩偶消失。
- 触摸触控板,玩偶移动。
- 点击触控板,玩偶跳跃。