주요 콘텐츠로 건너뛰기
버전: 2.1.1

간단한 위치 제어 튜토리얼

이 튜토리얼에서는 퀵 스타트 가이드에 소개된 개념을 기반으로 Unity 씬 내에서 동적 게임 오브젝트를 사용하여 Inverse3 디바이스의 커서 위치를 제어하는 방법을 보여줍니다.

소개

Inverse3 디바이스는 두 가지 제어 모드를 지원합니다: 강제 제어 그리고 위치 제어. 전자는 커서의 위치에 따라 힘을 조정하는 반면, 후자는 커서의 위치를 직접 조작합니다. 이 튜토리얼에서는 씬 설정을 활용하여 다이내믹 씬 튜토리얼의 강제 피드백를 사용하는 데 중점을 둡니다. CursorSetPosition 내에서 FixedUpdate 메서드를 사용하여 기기의 커서가 움직이는 게임 오브젝트를 따라갈 수 있도록 합니다.

장면 설정

에 설명된 장면 구성으로 시작하십시오. 다이내믹 씬 튜토리얼의 강제 피드백를 포함하는 햅틱 리그움직이는 공 게임 오브젝트에 의해 제어되는 MovableObject 컴포넌트입니다.

SpherePositionControl 컴포넌트 구현하기

교체 SphereForceFeedback 컴포넌트의 움직이는 공 라는 새 C# 스크립트가 포함된 게임 오브젝트입니다. SpherePositionControl.cs. 에서 다음 속성을 정의합니다. SpherePositionControl 클래스:

public Inverse3 inverse3;
public float minSyncDistance = 0.05f;
private bool _isCursorSynchronized;
  • inverse3: 인스펙터를 통해 설정한 Inverse3 디바이스 컴포넌트에 대한 참조입니다.
  • 최소 동기화 거리: 커서 동기화를 시작하기 위한 최소 거리 임계값입니다.
  • _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) 를 순간이동시키는 무빙볼 를 커서 위치로 이동합니다.

업데이트 및 수정 업데이트 방법

에서 Update 메서드를 사용하여 커서와 커서 사이의 거리에 따라 커서 동기화를 토글합니다. 움직이는 공:

private void Update()
{
var distance = Vector3.Distance(inverse3.CursorPosition, transform.position);
if (!_isCursorSynchronized && distance <= minSyncDistance)
{
StartSynchronizeCursor();
}
else if (_isCursorSynchronized && distance > minSyncDistance)
{
StopSynchronizeCursor();
}
}

In FixedUpdate를 클릭하고 커서 위치를 업데이트하여 움직이는 공 동기화가 활성화된 경우

private void FixedUpdate()
{
if (_isCursorSynchronized)
{
inverse3.CursorSetPosition(transform.position);
}
}

그래픽 렌더링 성능과 관계없이 위치 제어가 안정적인 프레임 속도로 작동하도록 하려면 FixedUpdate 메서드를 사용합니다.

초기화

In Awake()를 사용하여 움직이는 공 는 손에 쥐고 있는 것과 관계없이 Inverse3 디바이스가 접근할 수 있는 위치에서 시작됩니다:

private void Awake()
{
inverse3.DeviceOpened.AddListener(device =>
{
GetComponent<MovableObject>().SetTargetPosition(((Inverse3)device).WorkspaceCenter, teleport: true);
});
}

게임 플레이 경험

Inverse3 기기를 고정하고 충분한 공간이 있는지 확인합니다. 플레이 모드를 활성화하고 커서로 무빙볼에 접근하면 Inverse3가 무빙볼의 움직임을 따라 움직입니다. 키보드 입력을 사용하여 무빙볼을 움직일 수 있으며, 커서가 위치를 추적하는 기능을 시연할 수 있습니다.

간단한 위치 제어

소스 파일

이 튜토리얼의 전체 장면과 관련 파일은 다음 링크에서 확인할 수 있습니다. 튜토리얼 샘플을 생성할 수 있습니다. 여기에는 MovableObject 스크립트를 사용하여 키보드 입력을 통해 게임 오브젝트의 움직임을 제어하는 여러 예제에서 사용되었습니다.

SpherePositionControl.cs

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

using Haply.Inverse.Unity;
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 Inverse3 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.
if (inverse3 == null)
{
inverse3 = FindObjectOfType<Inverse3>();
}

// When inverse3 is ready, so the handedness is defined
inverse3.DeviceOpened.AddListener(device =>
{
var inverse3 = (Inverse3)device;
// 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(((Inverse3)device).WorkspaceCenter, teleport:true);
});
}

private void OnDisable()
{
// Ensure movement synchronization is disabled when the component is disabled.
StopSynchronizeCursor();
}

private void Update()
{
// 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.CursorSetPosition(transform.position);
}
}

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