자습서: 장치 매핑
이 튜토리얼에서는 Unity 프로젝트에서 기기를 수동으로 나열하고, 할당하고, 연결하는 방법을, Haply Inverse Service를 사용하여 설명합니다.
개요
DeviceMapper 컴포넌트는 Inverse3 및 VerseGrip과 같은 Haply 기기의 감지, 할당 및 장면의 디바이스 컨트롤러와의 연결을 관리합니다.
장면 구성
먼저 ‘Getting started Guide’에 설명된 대로 GameObject > Haply > Haptic Rig (two hands)를 선택하여 햅틱 리그를 생성하세요.
DeviceSelector 컴포넌트
다음과 같은 이름의 새로운 C# 스크립트를 만드세요. DeviceSelector.cs 그리고 이를 GameObject에 추가하세요 디바이스 매퍼 hinzu.
클래스 내에서 다음 속성을 정의하십시오. DeviceSelector:
public Inverse3Controller leftInverse3;
public Inverse3Controller rightInverse3;
private DeviceMapper _deviceMapper;
private string _message;
private bool _waitingForVerseGripHandednessConfirm;
디바이스 매퍼 설정하기
메서드 내에서 초기화하십시오 Awake 특성 _deviceMapper 그리고 이 행사에 등록하세요 Ready, 디바이스 매퍼가 이를 처리할 수 있는지 여부를 확인하기 위해.
private void Awake()
{
_deviceMapper = GetComponent<DeviceMapper>();
_deviceMapper.autoFetchDeviceList = false; // Disable auto-fetch to manually fetch the device list
_deviceMapper.autoAssign = false; // Disable auto-assign to manually map devices
_deviceMapper.autoConnect = false; // Disable auto-connect to manually connect devices
_deviceMapper.Ready.AddListener(OnDeviceMapperReady);
}
장치 컨트롤러 불러오기
디바이스 컨트롤러를 가져오려면 다음 메서드를 사용할 수 있습니다. GetInverse3Controller 그리고 GetVerseGripController 사용합니다.
// Get the first Inverse3 controller in the scene
leftInverse3 = _deviceMapper.GetInverse3Controller();
// Get the first Inverse3 controller in the scene with the specified handedness
leftInverse3 = _deviceMapper.GetInverse3Controller(HandednessType.Left);
// Get the Inverse3 controller in the scene with the specified device ID
leftInverse3 = _deviceMapper.GetInverse3Controller("1309");
// Get the first VerseGrip controller in the scene
verseGripController = _deviceMapper.GetVerseGripController();
// Get the VerseGrip controller in the scene associated with the specified Inverse3 controller
leftVerseGripController = _deviceMapper.GetVerseGripController(leftInverse3);
장치 컨트롤러의 손 선호도 선택
장치가 준비되기 전에, 속성을 사용하여 사용 방향을 설정할 수 있습니다. SelectedHandedness 설정합니다.
DeviceMapper는 선택한 손 선호도에 따라 연결된 장치를 컨트롤러에 자동으로 할당합니다.
// Select the left handedness for the left controller
leftInverse3.SelectedHandedness = HandednessType.Left;
// Select the right handedness for the right controller
rightInverse3.SelectedHandedness = HandednessType.Right;
장치 목록 불러오기
연결된 기기 목록을 확인하려면 다음 메서드를 사용할 수 있습니다. FetchDeviceListOnce 사용합니다.
// Fetch the list of connected devices
_deviceMapper.FetchDeviceListOnce();
장치 목록이 불러오면, 해당 컴포넌트는 DeviceMapper 그 사건 DeviceListReceived aus.
이 이벤트를 사용하여 사용자 인터페이스를 업데이트하거나 장치 목록과 관련된 다른 작업을 수행할 수 있습니다.
// Subscribe to the DeviceListReceived event
_deviceMapper.DeviceListReceived += OnDeviceListReceived;
private void OnDeviceListReceived(object sender, EventArgs e)
{
// Update the UI or perform any other operations
}
기기 할당
기기 목록이 불러오면, 다음 메서드를 사용하여 기기를 MapDevices 컨트롤러에 할당합니다.
// Map the devices to the controllers
if (_deviceMapper.CanMapDevices())
_deviceMapper.MapDevices();
이 방법 CanMapDevices 장치 목록이 완전한지, 그리고 컨트롤러가 할당 준비가 되어 있는지 확인합니다.
기기 연결하기
장치가 할당되면 다음 메서드를 사용하여 Connect WebSocket 서버에 연결하여 실시간 데이터를 수신하고 기기를 제어합니다.
다음 예제에서는 메서드 ProbeCursorPosition 장치가 준비되는 즉시 커서 위치 조회를 시작하려면 [auf]를 누르십시오.
// Connect the devices to the WebSocket server to receive real-time data
if (_deviceMapper.State == DeviceMapperState.MAPPING_COMPLETE)
_deviceMapper.Connect();
기기 교환
컨트롤러 간에 장치를 교체하려면 다음 메서드를 사용할 수 있습니다. SwapInverse3 또는 SwapVerseGrip 사용합니다.
다음 예시는 사용자에게 오른쪽 컨트롤러의 버튼을 눌러 손 선호도를 확인하거나, 손 선호도가 잘못되었을 경우 장치를 바꿔 잡도록 요청하는 방법을 보여줍니다.
메서드 내에서 OnDeviceMapperReady 이 이벤트를 구독합시다 ButtonDown 컨트롤러는 버튼 누름을 처리하고 사용자에게 손 선호도를 확인하도록 요청합니다.
private void OnDeviceMapperReady()
{
// Get the VerseGrip controllers using the DeviceMapper (must be done in Start or on DeviceMapper Ready event)
var leftVerseGrip = _deviceMapper.GetVerseGripController(leftInverse3);
var rightVerseGrip = _deviceMapper.GetVerseGripController(rightInverse3);
leftVerseGrip.ButtonDown.AddListener(OnButtonDown);
rightVerseGrip.ButtonDown.AddListener(OnButtonDown);
// Start waiting for button press on the right controller
_message = "Press the button on the right controller to confirm handedness.";
_waitingForVerseGripHandednessConfirm = true;
}
메서드 내에서 OnButtonDown 사용자가 오른손 컨트롤러의 버튼을 눌러 손 선호도를 확인했는지 확인해 봅시다.
private void OnButtonDown(VerseGripController verseGrip, VerseGripEventArgs args)
{
if (_waitingForVerseGripHandednessConfirm)
{
if (verseGrip != _deviceMapper.GetVerseGripController(rightInverse3))
{
_deviceMapper.SwapVerseGrip();
}
_waitingForVerseGripHandednessConfirm = false;
}
}
private void OnGUI()
{
if (_waitingForVerseGripHandednessConfirm)
{
GUILayout.Label(_message);
}
}
이 예제는 학습용으로 제공된 것이므로 실제 운영 환경에서는 사용해서는 안 됩니다. 응용 프로그램에서 손의 우·좌를 확인하는 데 적합한 방법을 찾아보십시오.
오류 처리
기기 할당 과정에서 오류가 발생하면 해당 이벤트는 Error triggered.
이 이벤트를 사용하여 오류를 처리하고 사용자에게 피드백을 제공할 수 있습니다.
// Subscribe to the Error event
_deviceMapper.ErrorOccured += OnError;
private void OnError(object sender, ErrorEventArgs e)
{
_message = e.ErrorMessage;
switch (e.ErrorCode)
{
// Handle the error...
}
}
원본 파일
이 예제의 완성된 씬과 관련 파일은 모두 Unity 패키지 관리자의 ‘예제 튜토리얼’을 통해 가져올 수 있습니다.
DeviceSelector.cs
해당 구성 요소 DeviceSelector 이 예제는 학습 목적으로만 사용되며, 실제 제작에는 사용해서는 안 됩니다.
이 예제는 Unity 프로젝트에서 기기를 나열하고, 할당하고, 연결하는 방법을 보여줍니다.
using Haply.Inverse;
using Haply.Inverse.DeviceControllers;
using Haply.Inverse.DeviceData;
using UnityEngine;
namespace Haply.Samples.Tutorials._7_DeviceMapping
{
public class DeviceSelector : MonoBehaviour
{
private DeviceMapper _deviceMapper;
public Inverse3Controller leftInverse3;
public Inverse3Controller rightInverse3;
private string _message;
private bool _waitingForVerseGripHandednessConfirm;
private void Awake()
{
_deviceMapper = GetComponent<DeviceMapper>();
_deviceMapper.autoAssign = false;
_deviceMapper.autoConnect = false;
_deviceMapper.autoFetchDeviceList = false;
_deviceMapper.Ready.AddListener(SetupVerseGripHandednessCheck);
_deviceMapper.Error += OnError;
leftInverse3.Ready.AddListener(OnDeviceReady);
rightInverse3.Ready.AddListener(OnDeviceReady);
}
// Start the verse grip handedness check (ask the user to press a button on the right controller)
private void SetupVerseGripHandednessCheck()
{
// Get the VerseGrip controllers using the DeviceMapper (must be done in Start or on DeviceMapper Ready event)
var leftVerseGrip = _deviceMapper.GetVerseGripController(leftInverse3);
var rightVerseGrip = _deviceMapper.GetVerseGripController(rightInverse3);
leftVerseGrip.ButtonDown.AddListener(OnButtonDown);
rightVerseGrip.ButtonDown.AddListener(OnButtonDown);
// Start waiting for button press on the right controller
_message = "Press the button on the right controller to confirm handedness.";
_waitingForVerseGripHandednessConfirm = true;
}
// Handle the button down event to confirm the verse grip handedness
private void OnButtonDown(VerseGripController verseGrip, VerseGripEventArgs args)
{
if (_waitingForVerseGripHandednessConfirm && args.Button is VerseGripButton.Button0 or VerseGripButton.Button1)
{
if (verseGrip == _deviceMapper.GetVerseGripController(rightInverse3))
{
_message = "VerseGrip handedness confirmed!";
}
else
{
_message = "Wrong controller button pressed. Swap the controllers.";
_deviceMapper.SwapVerseGrip();
}
_waitingForVerseGripHandednessConfirm = false;
}
else
{
_message = $"Button {args.Button} pressed on {verseGrip.DeviceId}";
}
}
// Handle the device ready event to start probing the cursor position
private void OnDeviceReady(Inverse3Controller device, Inverse3EventArgs _)
{
// Start probing the cursor position when the device is ready
device.ProbeCursorPosition();
}
// Handle errors from the device mapper
private void OnError(object sender, DeviceMapperErrorEventArgs e)
{
_message = e.ErrorMessage;
}
// Display the device list
private void DeviceListGUI()
{
if (_deviceMapper.GetNumInverse3() + _deviceMapper.GetNumVerseGrip() > 0)
{
GUILayout.Label("Connected devices:");
foreach (var device in _deviceMapper.GetInverse3Devices())
{
GUILayout.Label($"- {device}");
}
foreach (var device in _deviceMapper.GetVerseGripDevices())
{
GUILayout.Label($"- {device}");
}
}
}
// Display the device mapper state and actions.
private void DeviceMapperGUI()
{
switch (_deviceMapper.State)
{
case DeviceMapperState.UNINITIALIZED:
case DeviceMapperState.INITIALIZED:
if (GUILayout.Button(new GUIContent("List devices",
"Fetch the device list by HTTP request")))
{
_deviceMapper.FetchDeviceListOnce();
_message = "Fetching device list...";
}
break;
case DeviceMapperState.DEVICE_LIST_COMPLETE:
if (GUILayout.Button(new GUIContent("Map devices",
"Map the devices to the controllers according to the selected handedness")))
{
_deviceMapper.MapDevices();
_message = "Mapping devices...";
}
break;
case DeviceMapperState.MAPPING_COMPLETE:
if (!_deviceMapper.IsReady)
{
if (GUILayout.Button(new GUIContent("Connect",
"Connect the devices to WebSocket server to receive real-time data")))
{
_deviceMapper.Connect();
_message = "Connecting...";
}
}
break;
case DeviceMapperState.DEVICE_LIST_IN_PROGRESS:
case DeviceMapperState.MAPPING_IN_PROGRESS:
case DeviceMapperState.CONNECTED:
var style = new GUIStyle(GUI.skin.label) { normal = { textColor = Color.yellow } };
GUILayout.Label(_message, style);
break;
case DeviceMapperState.ERROR:
var errorStyle = new GUIStyle(GUI.skin.label) { normal = { textColor = Color.red } };
GUILayout.Label(_message, errorStyle);
if (GUILayout.Button(new GUIContent("Retry")))
{
_deviceMapper.Reset();
}
break;
}
}
// Display the device controller GUI for the inverse3 controller.
private void Inverse3ControllerGUI(Inverse3Controller controller)
{
// Before the device is assigned, we can select the handedness
if (!controller.Assigned)
{
GUILayout.Label("Inverse3Controller \u2192 <not assigned>", GUILayout.Width(800));
if (GUILayout.Button($"Filter: {controller.SelectedHandedness}"))
{
switch (controller.SelectedHandedness)
{
case HandednessType.Left:
controller.SelectedHandedness = HandednessType.Right;
break;
case HandednessType.Right:
controller.SelectedHandedness = HandednessType.Any;
break;
case HandednessType.Any:
controller.SelectedHandedness = HandednessType.Left;
break;
}
}
}
// Once the device is assigned, devices can be swapped
else
{
GUILayout.Label($"Inverse3Controller \u2192 #{controller.DeviceId}.{controller.Handedness}", GUILayout.Width(800));
// Swap the two inverse3 controllers' assigned devices
if (GUILayout.Button(new GUIContent("Swap inverse3",
"Swap the two inverse3 controller's assigned devices")))
{
_deviceMapper.SwapInverse3();
_waitingForVerseGripHandednessConfirm = true;
}
}
// Enable or disable the cursor position update
var probing= GUILayout.Toggle(controller.IsProbeCursorPosition, "Probe cursor position");
if (controller.IsReady && probing != controller.IsProbeCursorPosition)
{
controller.ProbeCursorPosition(probing);
}
}
private void VerseGripControllerGUI(VerseGripController controller)
{
// Before the device is assigned, we can select the VerseGrip type
if (!controller.Assigned)
{
GUILayout.Label("VerseGripController \u2192 <not assigned>", GUILayout.Width(800));
if (GUILayout.Button($"Filter: {controller.verseGripTypeFilter}"))
{
switch (controller.verseGripTypeFilter)
{
case VerseGripType.Wired:
controller.verseGripTypeFilter = VerseGripType.Wireless;
break;
case VerseGripType.Wireless:
controller.verseGripTypeFilter = VerseGripType.Any;
break;
case VerseGripType.Any:
controller.verseGripTypeFilter = VerseGripType.Wired;
break;
}
}
}
// Once the device is ready, devices can be swapped
else
{
GUILayout.Label($"VerseGripController \u2192 #{controller.DeviceId}.{controller.VerseGripType}", GUILayout.Width(800));
// Swap the two verse grip controllers' assigned devices
if (GUILayout.Button("Swap verse grip"))
{
_deviceMapper.SwapVerseGrip();
_waitingForVerseGripHandednessConfirm = true;
}
}
}
// Display the GUI
private void OnGUI()
{
// Show the device mapper state and actions
GUILayout.BeginArea(new Rect(10, 10, 400, 200), new GUIStyle(GUI.skin.box));
DeviceMapperGUI();
GUILayout.Space(10);
// Show the device list
DeviceListGUI();
GUILayout.EndArea();
// Show the left inverse3 controller
var leftRect = new Rect(0, Screen.height - 200, 300, 200);
leftRect.x = 10;
GUILayout.BeginArea(leftRect, new GUIStyle(GUI.skin.box));
GUILayout.Label(leftInverse3.gameObject.name, GUILayout.Width(600));
Inverse3ControllerGUI(leftInverse3);
GUILayout.Space(10);
// Show the associated verse grip controller
var leftVerseGripController = _deviceMapper.GetVerseGripController(leftInverse3);
VerseGripControllerGUI(leftVerseGripController);
GUILayout.EndArea();
// Show the right controller
var rightRect = new Rect(0, Screen.height - 200, 300, 200);
rightRect.x = Screen.width - rightRect.width - 10;
GUILayout.BeginArea(rightRect, new GUIStyle(GUI.skin.box));
GUILayout.Label(rightInverse3.gameObject.name, GUILayout.Width(600));
Inverse3ControllerGUI(rightInverse3);
GUILayout.Space(10);
// Show the associated verse grip controller
var rightVerseGripController = _deviceMapper.GetVerseGripController(rightInverse3);
VerseGripControllerGUI(rightVerseGripController);
GUILayout.EndArea();
}
}
}