跳转至主要内容

位置控制简易教程

本教程将向您展示如何在 Unity 场景中通过一个动态 GameObject 来控制Inverse3 设备的光标位置,并在此基础上进一步扩展了“入门指南”中的相关概念。

引言​

Inverse3 设备支持两种控制模式: 力控制 und 位置控制. 力控制会根据光标位置调整力,而位置控制则直接控制光标位置。 本教程使用了来自 动态场景中的力反馈教程 并侧重于使用 CursorSetPosition innerhalb der Methode FixedUpdate,以便设备的光标能够跟随移动中的 GameObject。

场景设置​

请从 动态场景中的力反馈教程, 其中一个 触觉装置 以及一个 GameObject 移动球 包括由该组件 MovableObject 由……控制。

SpherePositionControl 组件的实现​

更换该部件 球体力反馈 am GameObject 移动球 通过一个名为 SpherePositionControl.cs. 在类中定义 SpherePositionControl 具有以下特性:

public Inverse3 inverse3;
public float minSyncDistance = 0.05f;
private bool _isCursorSynchronized;
  • inverse3: 指在“检查器”中设置的Inverse3 设备的组件。
  • minSyncDistance:开始进行光标同步时的最小距离。
  • _isCursorSynchronized:一个标志,用于指示光标的移动是否与“移动球”同步。

同步逻辑​

请实现相关方法,根据与移动球的距离来启动和停止光标同步:

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) 被使用,从而导致 移动球 被传送到光标位置。

Methoden 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 设备,并确保留有足够的空间。 当您启用“播放”模式并将光标移向“移动球”时,Inverse3 设备会跟随“移动球”的移动。 通过键盘输入可以移动“移动球”,从而演示光标追踪其位置的能力。

简单位置控制

源文件​

本教程的完整场景及相关文件,请参见示例 教程 我是 Unity 的包管理器。 其中包括该脚本 MovableObject,该功能在多个示例中被用于通过键盘输入来控制 GameObject 的移动。

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();
}
}
}