Anleitung: Gerätezuordnung
Dieses Tutorial zeigt, wie Geräte in einem Unity-Projekt manuell aufgelistet, zugeordnet und verbunden werden – und zwar mithilfe des „Haply -Inverse-Service“.
Überblick
Die Komponente „DeviceMapper“ verwaltet die Erkennung, Zuordnung und Verbindung von „ Haply “-Geräten wie „ Inverse3 “ und „VerseGrip“ mit den Device-Controllern der Szene.
Szenenaufbau
Erstellen Sie zunächst ein Haptic Rig: „GameObject“ > „ Haply “ > „Haptic Rig (two hands)“, wie im „Getting Started Guide“ beschrieben.
DeviceSelector-Komponente
Erstellen Sie ein neues C#-Skript mit dem Namen DeviceSelector.cs und fügen Sie es dem GameObject hinzu Geräte-Mapper hinzu.
Definieren Sie die folgenden Eigenschaften innerhalb der Klasse DeviceSelector:
public Inverse3Controller leftInverse3;
public Inverse3Controller rightInverse3;
private DeviceMapper _deviceMapper;
private string _message;
private bool _waitingForVerseGripHandednessConfirm;
Device Mapper einrichten
Initialisieren Sie in der Methode Awake die Eigenschaft _deviceMapper und abonnieren Sie die Veranstaltung Ready, um die Bereitschaft des Device Mappers zu verarbeiten.
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);
}
Gerätecontroller abrufen
Um die Gerätetreiber abzurufen, können Sie die Methoden GetInverse3Controller und GetVerseGripController verwenden.
// 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);
Auswahl der Händigkeit der Gerätesteuerungen
Bevor das Gerät betriebsbereit ist, können Sie die Händigkeit mithilfe der Eigenschaft SelectedHandedness festlegen.
Der DeviceMapper ordnet die angeschlossenen Geräte anhand der ausgewählten Händigkeit automatisch den Controllern zu.
// Select the left handedness for the left controller
leftInverse3.SelectedHandedness = HandednessType.Left;
// Select the right handedness for the right controller
rightInverse3.SelectedHandedness = HandednessType.Right;
Geräteliste abrufen
Um die Liste der verbundenen Geräte abzurufen, können Sie die Methode FetchDeviceListOnce verwenden.
// Fetch the list of connected devices
_deviceMapper.FetchDeviceListOnce();
Sobald die Geräteliste abgerufen wurde, löst die Komponente DeviceMapper das Ereignis DeviceListReceived aus.
Sie können dieses Ereignis nutzen, um die Benutzeroberfläche zu aktualisieren oder andere Vorgänge im Zusammenhang mit der Geräteliste durchzuführen.
// Subscribe to the DeviceListReceived event
_deviceMapper.DeviceListReceived += OnDeviceListReceived;
private void OnDeviceListReceived(object sender, EventArgs e)
{
// Update the UI or perform any other operations
}
Geräte zuweisen
Sobald die Geräteliste abgerufen wurde, können Sie die Geräte mithilfe der Methode MapDevices den Controllern zuordnen.
// Map the devices to the controllers
if (_deviceMapper.CanMapDevices())
_deviceMapper.MapDevices();
Die Methode CanMapDevices prüft, ob die Geräteliste vollständig ist und ob die Controller für die Zuordnung bereit sind.
Geräte verbinden
Sobald die Geräte zugeordnet sind, können Sie sie mithilfe der Methode Connect eine Verbindung zum WebSocket-Server herstellen, um Echtzeitdaten zu empfangen und die Geräte zu steuern.
Im folgenden Beispiel rufen wir die Methode ProbeCursorPosition auf, um die Abfrage der Cursorposition zu starten, sobald das Gerät bereit ist.
// Connect the devices to the WebSocket server to receive real-time data
if (_deviceMapper.State == DeviceMapperState.MAPPING_COMPLETE)
_deviceMapper.Connect();
Geräte austauschen
Um die Geräte zwischen den Controllern auszutauschen, können Sie die Methode SwapInverse3 oder SwapVerseGrip verwenden.
Das folgende Beispiel zeigt, wie Sie den Benutzer auffordern können, eine Taste am rechten Controller zu drücken, um die Händigkeit zu bestätigen, oder die Geräte zu vertauschen, falls die Händigkeit falsch ist.
In der Methode OnDeviceMapperReady Wir abonnieren die Veranstaltung ButtonDown der Controller, um den Tastendruck zu verarbeiten und den Benutzer aufzufordern, die Händigkeit zu bestätigen.
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;
}
In der Methode OnButtonDown Wir prüfen, ob der Benutzer die Taste am rechten Controller gedrückt hat, um die Händigkeit zu bestätigen.
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);
}
}
Dieses Beispiel dient zu Lernzwecken und sollte nicht in der Produktion verwendet werden. Finden Sie in Ihrer Anwendung eine geeignete Methode, um die Händigkeit zu bestätigen.
Fehlerbehandlung
Tritt während des Gerätezuordnungsprozesses ein Fehler auf, wird das Ereignis Error ausgelöst.
Sie können dieses Ereignis nutzen, um Fehler zu behandeln und dem Benutzer eine Rückmeldung zu geben.
// Subscribe to the Error event
_deviceMapper.ErrorOccured += OnError;
private void OnError(object sender, ErrorEventArgs e)
{
_message = e.ErrorMessage;
switch (e.ErrorCode)
{
// Handle the error...
}
}
Quelldateien
Die fertige Szene und alle zugehörigen Dateien dieses Beispiels können über die Beispiel-Tutorials im Paketmanager von Unity importiert werden.
DeviceSelector.cs
Die Komponente DeviceSelector dient zu Lernzwecken und sollte nicht in der Produktion verwendet werden.
Sie zeigt, wie Geräte in einem Unity-Projekt aufgelistet, zugeordnet und verbunden werden.
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();
}
}
}