Skip to main content
Version : 3.1.3

Tutoriel sur le mappage des appareils

Ce tutoriel montre comment lister, cartographier et connecter manuellement des appareils dans un projet Unity en utilisant le serviceHaply Inverse.

Vue d'ensemble

Le composant DeviceMapper gère la découverte, le mappage et la connexion des appareils Haply , tels que l'Inverse3 et le VerseGrip, avec les contrôleurs d'appareils de la scène.

Configuration de la scène

Commencez par créer un Haptic Rig : GameObject > Haply > Haptic Rig (deux mains), comme indiqué dans le Guide de démarrage rapide.

Composant DeviceSelector

Créer un nouveau script C# nommé DeviceSelector.cs et l'attacher au Mappage d'appareils GameObject. Définissez les propriétés suivantes dans le fichier DeviceSelector classe :

public Inverse3Controller leftInverse3;
public Inverse3Controller rightInverse3;

private DeviceMapper _deviceMapper;
private string _message;
private bool _waitingForVerseGripHandednessConfirm;

Configuration de Device Mapper

Dans le cadre de la Awake initialiser la méthode _deviceMapper et s'abonner à la propriété Ready pour gérer l'état de préparation du mappeur d'appareils.

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

Obtenir des contrôleurs de périphériques

Pour obtenir les contrôleurs de périphériques, vous pouvez utiliser la commande GetInverse3Controller et GetVerseGripController des méthodes.

// 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);

Sélection de la main du contrôleur de l'appareil

Avant que l'appareil ne soit prêt, vous pouvez sélectionner la main en utilisant le bouton SelectedHandedness propriété. Le DeviceMapper attribuera automatiquement les appareils connectés aux contrôleurs en fonction de la main sélectionnée.

// Select the left handedness for the left controller
leftInverse3.SelectedHandedness = HandednessType.Left;

// Select the right handedness for the right controller
rightInverse3.SelectedHandedness = HandednessType.Right;

Récupération de la liste des appareils

Pour obtenir la liste des appareils connectés, vous pouvez utiliser la fonction FetchDeviceListOnce méthode.

// Fetch the list of connected devices
_deviceMapper.FetchDeviceListOnce();

Une fois la liste des appareils récupérée, la fonction DeviceMapper déclenchera l'application DeviceListReceived événement. Vous pouvez utiliser cet événement pour mettre à jour l'interface utilisateur ou effectuer toute autre opération liée à la liste des appareils.

// Subscribe to the DeviceListReceived event
_deviceMapper.DeviceListReceived += OnDeviceListReceived;

private void OnDeviceListReceived(object sender, EventArgs e)
{
// Update the UI or perform any other operations
}

Dispositifs de cartographie

Une fois la liste des appareils récupérée, vous pouvez affecter les appareils aux contrôleurs à l'aide de la commande MapDevices méthode.

// Map the devices to the controllers
if (_deviceMapper.CanMapDevices())
_deviceMapper.MapDevices();

Les CanMapDevices vérifie si la liste des appareils est complète et si les contrôleurs sont prêts pour le mappage.

Dispositifs de connexion

Une fois les appareils mappés, vous pouvez les connecter au serveur WebSocket à l'aide de la commande Connect méthode permettant de recevoir des données en temps réel et de contrôler les appareils.

info

Dans l'exemple suivant, nous appelons le ProbeCursorPosition pour commencer à sonder la position du curseur lorsque l'appareil est prêt.

// Connect the devices to the WebSocket server to receive real-time data
if (_deviceMapper.State == DeviceMapperState.MAPPING_COMPLETE)
_deviceMapper.Connect();

Remplacement des dispositifs

Pour permuter les périphériques entre les contrôleurs, vous pouvez utiliser la commande SwapInverse3 ou SwapVerseGrip méthode.

L'exemple suivant montre comment demander à l'utilisateur d'appuyer sur un bouton du contrôleur droit pour confirmer la position de la main, ou d'intervertir les dispositifs si la position de la main est incorrecte.

Dans le cadre de la OnDeviceMapperReady nous nous abonnons à la méthode ButtonDown des contrôleurs pour gérer l'appui sur le bouton et demander à l'utilisateur de confirmer la main.

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

Dans le cadre de la OnButtonDown nous vérifions si l'utilisateur a appuyé sur le bouton de la manette de droite pour confirmer qu'il est droitier.

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

Cet exemple est donné à titre didactique et ne doit pas être utilisé en production. Trouvez une méthode appropriée pour confirmer la main dans votre application.

Gestion des erreurs

Si une erreur se produit au cours du processus de mappage des appareils, l'icône Error sera déclenché. Vous pouvez utiliser cet événement pour gérer les erreurs et fournir un retour d'information à l'utilisateur.

// Subscribe to the Error event
_deviceMapper.ErrorOccured += OnError;

private void OnError(object sender, ErrorEventArgs e)
{
_message = e.ErrorMessage;
switch (e.ErrorCode)
{
// Handle the error...
}
}

Fichiers sources

La scène finale et tous les fichiers associés utilisés dans cet exemple peuvent être importés depuis l'échantillon Tutorials dans le gestionnaire de paquets d'Unity.

DeviceSelector.cs

avertissement

Les DeviceSelector est utilisé à des fins didactiques et ne doit pas être utilisé en production. Il montre comment lister, cartographier et connecter des appareils dans un projet 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();
}
}
}