跳至主要内容
版本: 2.0.0

VerseGrip 位置控制教程

本教程演示了如何使用 VerseGrip 的旋转功能直接控制 Inverse3 设备光标的位置,从而绕过 Unity 主线程进行高频更新。

导言

快速入门指南本教程的目的是根据 VerseGrip 设备以更高频率(1~4kHz)的旋转动态调整 Inverse3 光标的位置。 这是通过利用 DeviceStateChanged 事件,由触觉线程触发。

场景设置

首先创建触觉装配:GameObject > Haply > Haptic Rig(单手),详见《快速入门指南》

VerseGripPositionControl 组件

创建一个新的 C# 脚本,名为 VerseGripPositionControl.cs 并将其连接到 触觉起源 游戏对象 在 VerseGripPositionControl 类:

public Inverse3 inverse3;
public VerseGrip verseGrip;

[Range(0, 1)]
public float speed = 0.5f;

[Range(0, 0.2f)]
public float movementLimitRadius = 0.2f;

private Vector3 _targetPosition;
  • inverse3:Inverse3设备的引用,通过检查器设置。
  • verseGrip:用于光标控制的 VerseGrip 设备的引用。
  • speed:光标移动的速度。
  • movementLimitRadius:光标从初始位置移动的最大距离。
  • _targetPosition(目标位置):光标移动的目标位置。

实施 OnDeviceStateChanged 方法,根据 VerseGrip 的旋转和按钮输入计算光标的目标位置:

private void OnDeviceStateChanged(VerseGrip grip)
{
// Calculate the direction based on the VerseGrip's rotation
var direction = grip.LocalRotation * Vector3.forward;

// Check if the VerseGrip button is pressed down
if (grip.GetButtonDown())
{
// Initialize target position
_targetPosition = inverse3.LocalPosition;
}

// Check if the VerseGrip button is being held down
if (grip.GetButton())
{
// Move the target position toward the grip direction
_targetPosition += direction * (0.0025f * speed);

// Clamp the target position within the movement limit radius
var workspaceCenter = inverse3.WorkspaceCenter;
_targetPosition = Vector3.ClampMagnitude(_targetPosition - workspaceCenter, movementLimitRadius)
+ workspaceCenter;

// Move cursor to new position
inverse3.CursorSetLocalPosition(_targetPosition);
}
}

注册和注销 DeviceStateChanged 事件中 OnEnableOnDisable.

/// Subscribes to the DeviceStateChanged event.
private void OnEnable()
{
verseGrip.DeviceStateChanged += OnDeviceStateChanged;
}

/// Unsubscribes from the DeviceStateChanged event.
private void OnDisable()
{
verseGrip.DeviceStateChanged -= OnDeviceStateChanged;
}

可选:Update 方法,让用户可以重置 Inverse3 的力值。

private void Update()
{
// Check for space key to disable position control
if (Input.GetKeyDown(KeyCode.Space))
{
// Reset cursor force to disable position control
inverse3.TryResetForce();
}
}

游戏玩法

  • 固定好 Inverse3 设备,确保有足够的活动空间。
  • 进入播放模式并按住反向 3 光标。
  • 旋转 VerseGrip,观察光标在 Unity 场景中的移动,这与 VerseGrip 的方向直接对应。
  • 按下 VerseGrip 的按钮,Inverse3 的光标就会沿着 VerseGrip 的旋转方向移动,从而实现实时控制。

诗句手柄移动球

图片说明了光标模型,为清晰起见,突出显示了其前轴。 有关自定义光标模型的更多详情,请参阅光标文档

源文件

本示例使用的最终场景和所有相关文件都可以从 Unity 软件包管理器中的教程示例中导入。

VerseGripPositionControl.cs

/*
* Copyright 2024 Haply Robotics Inc. All rights reserved.
*/

using Haply.Inverse.Unity;
using UnityEngine;

namespace Haply.Samples.Tutorials._6_VerseGripPositionControl
{
/// <summary>
/// Demonstrates how to control the device cursor position using the VerseGrip.
/// </summary>
public class VerseGripPositionControl : MonoBehaviour
{
// Must be assigned in inspector
public Inverse3 inverse3;
public VerseGrip verseGrip;

[Tooltip("Cursor moving speed")]
[Range(0, 1)]
public float speed = 0.5f;

[Tooltip("Maximum radius for cursor movement")]
[Range(0, 0.2f)]
public float movementLimitRadius = 0.2f;

private Vector3 _targetPosition; // Target position for the cursor

/// <summary>
/// Subscribes to the DeviceStateChanged event.
/// </summary>
private void OnEnable()
{
verseGrip.DeviceStateChanged += OnDeviceStateChanged;
}

/// <summary>
/// Unsubscribes from the DeviceStateChanged event.
/// </summary>
private void OnDisable()
{
verseGrip.DeviceStateChanged -= OnDeviceStateChanged;
}

private void Update()
{
// Check for space key to disable position control
if (Input.GetKeyDown(KeyCode.Space))
{
// Reset cursor force to disable position control
inverse3.TryResetForce();
}
}

private void OnDeviceStateChanged(VerseGrip grip)
{
// Calculate the direction based on the VerseGrip's rotation
var direction = grip.LocalRotation * Vector3.forward;

// Check if the VerseGrip button is pressed down
if (grip.GetButtonDown())
{
// Initialize target position
_targetPosition = inverse3.LocalPosition;
}

// Check if the VerseGrip button is being held down
if (grip.GetButton())
{
// Move the target position toward the grip direction
_targetPosition += direction * (0.0025f * speed);

// Clamp the target position within the movement limit radius
var workspaceCenter = inverse3.WorkspaceCenter;
_targetPosition = Vector3.ClampMagnitude(_targetPosition - workspaceCenter, movementLimitRadius)
+ workspaceCenter;

// Move cursor to new position
inverse3.CursorSetLocalPosition(_targetPosition);
}
}
}