简单的位置控制教程
在本教程中,我们将基于入门指南中介绍的概念,讲解如何利用动态游戏对象在 Unity 场景中控制Inverse3 设备的光标位置。
前言
Inverse3 该设备,力控制(力控)与位置控制支持(位置控制)的两种控制模式。
前者根据光标位置调整力度,而后者则直接控制光标位置。
在本教程中,动态场景中力反馈的教程 利用场景设置,FixedUpdate 在方法内 CursorSetPosition 使用该功能,使设备的光标能够跟随游戏对象的移动。
场景设置
动态场景中力反馈的教程 我们将从前面介绍的场景结构开始。该场景中,触觉装置 于是,MovableObject 由组件控制 移动球 其中包含游戏对象。
SpherePositionControl 组件的实现
移动球 在游戏对象上的 球体力反馈 将组件添加到新的 C# 脚本中 SpherePositionControl.cs 替换为。
SpherePositionControl 在类中,定义以下属性:
public Inverse3 inverse3;
public float minSyncDistance = 0.05f;
private bool _isCursorSynchronized;
- inverse3: 这是在检查器中设置的、指向Inverse3 设备组件的引用。
- minSyncDistance:这是开始同步光标的最小距离阈值。
- _isCursorSynchronized:一个标志,用于指示光标移动是否与“Moving Ball”同步。
同期逻辑
实现一个方法,根据与“移动球”的距离来启动和停止光标的同步:
private void StartSynchronizeCursor()
{
var cursorPosition = inverse3.Cursor.transform.position;
GetComponent<MovableObject>().SetTargetPosition(cursorPosition, teleport: true);
_isCursorSynchronized = true;
}
private void StopSynchronizeCursor()
{
_isCursorSynchronized = !inverse3.Release();
}
在这里
MovableObject.SetTargetPosition(position, teleport:true)使用。这样,移动球 将传送到光标位置。
Update 方法与 FixedUpdate 方法
Update 在该方法中,光标和 移动球 根据距离,切换光标的同步方式:
private void Update()
{
var distance = Vector3.Distance(inverse3.CursorPosition, transform.position);
if (!_isCursorSynchronized && distance <= minSyncDistance)
{
StartSynchronizeCursor();
}
else if (_isCursorSynchronized && distance > minSyncDistance)
{
StopSynchronizeCursor();
}
}
如果同期有效,则FixedUpdate 在其中将光标定位到 移动球 更新为与以下位置一致:
private void FixedUpdate()
{
if (_isCursorSynchronized)
{
inverse3.SetCursorPosition(transform.position);
}
}
为了确保位置控制不受图形渲染性能的影响,并能以稳定的帧率运行,请使用 FixedUpdate 方法。
初始化
Awake() 在该位置内,无论惯用手是哪只,都应将其放置在可从Inverse3 设备访问的位置 移动球 请确保其开始运行:
private void Awake()
{
inverse3.Ready.AddListener(device =>
{
GetComponent<MovableObject>().SetTargetPosition(((Inverse3)device).WorkspaceCenterLocalPosition, teleport: true);
});
}
游戏体验
Inverse3 请将设备牢固固定,并确保留有足够的空间。 启用“播放”模式,将光标移至“Moving Ball”附近,此时“Inverse3 ”将跟随“Moving Ball”的移动。 您可以通过键盘输入移动“Moving Ball”,并确认光标能够跟踪其位置。

源文件
本教程的完整场景及相关文件可在 Unity Package Manager 中的 教程 在示例中。
其中包含 MovableObject 其中包含一个脚本。该脚本在多个示例中被用于通过键盘输入来控制游戏对象的移动。
SpherePositionControl.cs
/*
* Copyright 2024 Haply Robotics Inc. All rights reserved.
*/
using Haply.Inverse.DeviceControllers;
using Haply.Samples.Tutorials.Utils;
using UnityEngine;
namespace Haply.Samples.Tutorials._5_SimplePositionControl
{
/// <summary>
/// Controls the Inverse3 cursor position based on the current position of this GameObject.
/// When the GameObject is within a specified distance from the cursor, it initiates synchronized control,
/// allowing the cursor to follow the GameObject's movements.
/// </summary>
[RequireComponent(typeof(MovableObject))]
public class SpherePositionControl : MonoBehaviour
{
public Inverse3Controller inverse3;
[Tooltip("Minimum distance required to initiate synchronized control between this GameObject and the Inverse3 cursor.")]
[Range(0, 1)]
public float minSyncDistance = 0.05f;
private bool _isCursorSynchronized;
private void Awake()
{
// Ensure inverse3 is set, finding it in the scene if necessary.
inverse3 ??= FindFirstObjectByType<Inverse3Controller>();
// When inverse3 is ready, so the handedness is defined
inverse3.Ready.AddListener((device, args) =>
{
// Teleport the sphere to its workspace center to ensure it can be reached,
// regardless of whether the device is left or right-handed. This ensures the GameObject starts in a
// position that is accessible by the Inverse3 device.
GetComponent<MovableObject>().SetTargetPosition(device.WorkspaceCenterLocalPosition, teleport:true);
});
}
private void OnDisable()
{
// Ensure movement synchronization is disabled when the component is disabled.
StopSynchronizeCursor();
inverse3.Release();
}
private void Update()
{
if (!inverse3.IsReady)
{
return;
}
// Calculate the distance between the Inverse3 position and this object's position.
var distance = Vector3.Distance(inverse3.CursorPosition, transform.position);
// Enable synchronized movement if within the minimum sync distance and not already synced.
if (!_isCursorSynchronized && distance <= minSyncDistance)
{
StartSynchronizeCursor();
}
// Disable synchronized movement if outside the minimum sync distance and currently synced.
else if (_isCursorSynchronized && distance > minSyncDistance)
{
StopSynchronizeCursor();
}
}
private void FixedUpdate()
{
if (_isCursorSynchronized)
{
// If in sync, set the Inverse3 cursor position to this object's position.
inverse3.SetCursorPosition(transform.position);
}
else
{
inverse3.ProbeCursorPosition(true);
}
}
private void StartSynchronizeCursor()
{
// Get the current cursor position.
var cursorPosition = inverse3.Cursor.transform.position;
// Teleport this object to the cursor position to avoid a sudden jump when position control starts.
GetComponent<MovableObject>().SetTargetPosition(cursorPosition, teleport:true);
// Start synchronizing the movement of this object with the cursor.
_isCursorSynchronized = true;
}
private void StopSynchronizeCursor()
{
// Stop synchronizing the movement.
_isCursorSynchronized = !inverse3.Release();
}
}
}