Interaction — MRTK2

Interactable

Le Interactable composant est un conteneur tout-en-un pour rendre tout objet facilement accessible et réactif à l’entrée. Interactionable agit comme un catch-all pour tous les types d’entrée, y compris le toucher, les rayons de main, la parole, etc. et en entonnoir ces interactions dans les événements et les réponses de thème visuel . Ce composant offre un moyen simple d’effectuer des boutons, de modifier la couleur sur les objets avec focus et bien plus encore.

Guide pratique pour configurer l’interaction

Le composant permet trois sections principales de la configuration :

  1. Configuration générale des entrées
  2. Thèmes visuels ciblés sur plusieurs GameObjects
  3. Gestionnaires d’événements

Paramètres d’entrée généraux

General Interactable Settings

États

Les états sont un paramètre ScriptableObject qui définit les phases d’interactions, comme appuyez ou observé, pour les profils interagir et les thèmes visuels.

DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) est fourni avec MRTK out-of-box et est le paramètre par défaut pour les composants interactables.

States ScriptableObject example in inspector

La ressource DefaultInteractableStates contient quatre états et utilise l’implémentation du InteractableStates modèle d’état.

  • Valeur par défaut : Rien ne se passe, il s’agit de l’état de base le plus isolé.

  • Focus : L’objet est pointé vers le point. Il s’agit d’un seul état, aucun autre état n’est actuellement défini, mais il sort du classement par défaut.

  • Appuyez sur : l’objet est pointé et un bouton ou une main appuie. L’état pressé est classé par défaut et Focus. Cet état sera également défini en tant que secours sur La presse physique.

  • Désactivé : le bouton ne doit pas être interactif et les commentaires visuels permettent à l’utilisateur de savoir si, pour une raison quelconque, ce bouton n’est pas utilisable à ce stade. En théorie, l’état désactivé peut contenir tous les autres états, mais quand Activé est désactivé, l’état Désactivé l’emporte sur tous les autres états.

Une valeur de bit (#) est attribuée à l’état en fonction de l’ordre dans la liste.

Notes

Il est généralement recommandé d’utiliser defaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) lors de la création de composants interactables .

Toutefois, il existe 17 états pouvant être utilisés pour générer des thèmes, bien que certains soient destinés à être pilotés par d’autres composants. Voici la liste des fonctionnalités intégrées.

  • Visité : l’interaction a été cliquée.
  • Bascule : le bouton est dans un état désactivé ou un index dimension est un nombre impair.
  • Mouvement : la main ou le contrôleur a été enfoncé et a été déplacé de la position d’origine.
  • VoiceCommand : une commande vocale a été utilisée pour déclencher l’interaction.
  • PhysicalTouch : une entrée tactile est actuellement détectée, utilisez NearInteractionTouchable pour activer.
  • Saisir : Une main se saisit actuellement dans les limites de l’objet, utilisez NearInteractionGrabbable pour activer

Activé

Bascule si un interactionable démarre ou non. Cela correspond au Interactable.IsEnabled code.

La propriété interactive est différente de celle configurée via GameObject/Component (par exemple, SetActive, etc.). La désactivation de GameObject ou De MonoBehaviour interagissant désactive tout ce qui se trouve dans la classe en cours d’exécution, notamment les entrées, les thèmes visuels, les événements, etc. La désactivation via Interactable.IsEnabled désactivera la plupart de la gestion des entrées, la réinitialisation des états d’entrée associés. Toutefois, la classe exécute toujours chaque frame et reçoit les événements d’entrée qui seront ignorés. Cela est utile pour afficher l’interaction dans un état désactivé qui peut être effectué via des thèmes visuels. Il s’agit généralement d’un bouton d’envoi qui attend que tous les champs d’entrée requis soient terminés.

Actions d’entrée

Sélectionnez l’action d’entrée à partir du profil de mappage de configuration d’entrée ou de contrôleur auquel le composant interagir doit réagir.

Cette propriété peut être configurée au moment de l’exécution dans le code via Interactable.InputAction.

IsGlobal

Si la valeur est true, cela marque le composant comme écouteur d’entrée global pour l’action d’entrée sélectionnée. Le comportement par défaut est false, ce qui limitera l’entrée uniquement à ce collisionneur interagissant /GameObject.

Cette propriété peut être configurée au moment de l’exécution dans le code via Interactable.IsGlobal.

Commande Speech

Commande speech, à partir du profil de commandes speech MRTK, pour déclencher un événement OnClick pour l’interaction vocale.

Cette propriété peut être configurée au moment de l’exécution dans le code via Interactable.VoiceCommand.

Nécessite le focus

Si la valeur est true, la commande vocale active uniquement l’interaction si et uniquement si elle a déjà le focus à partir d’un pointeur. Si la valeur est false, l’interaction peut agir en tant qu’écouteur global pour la commande vocale sélectionnée. Le comportement par défaut est vrai, car plusieurs écouteurs vocaux globaux peuvent être difficiles à organiser dans une scène.

Cette propriété peut être configurée au moment de l’exécution dans le code via Interactable.VoiceRequiresFocus.

Mode sélection

Cette propriété définit la logique de sélection. Lorsqu’un interactionable est cliqué, il itère dans un niveau de dimension suivant. Les dimensions sont similaires au classement et définissent un état en dehors des entrées (c’est-à-dire le focus, la pression, etc.). Elles sont utiles pour définir des états bascule ou d’autres états à plusieurs classements associés à un bouton. Le niveau dimension actuel est suivi par Interactable.DimensionIndex.

Les modes de sélection disponibles sont les suivants :

  • Bouton - Dimensions = 1, Simple Clickable Interactable
  • Bascule - Dimensions = 2, alternatives interagissantesentre/l’état désactivé
  • Multidimension - Dimensions> = 3, chaque clic augmente le niveau de dimension actuel + 1. Utile pour définir un état de bouton sur une liste, etc.

L’interaction peut également permettre à plusieurs thèmes d’être définis par dimension. Par exemple, lorsque SelectionMode=Toggle, un thème peut être appliqué lorsque l’interaction estdésélectionnée et qu’un autre thème est appliqué lorsque le composant est sélectionné.

Le mode sélection actuel peut être interrogé au moment de l’exécution via Interactable.ButtonMode. La mise à jour du mode au moment de l’exécution peut être obtenue en définissant la Interactable.Dimensions propriété pour qu’elle corresponde à la fonctionnalité souhaitée. En outre, la dimension actuelle, utile pour le bouton bascule et les modes Multi-Dimension , est accessible via Interactable.CurrentDimension.

Profils interagissants

Les profils sont des éléments qui créent une relation entre un GameObject et un thème visuel. Le profil définit le contenu qui sera manipulé par un thème lorsqu’une modification d’état se produit.

Les thèmes fonctionnent beaucoup comme des matériaux. Ils sont des objets scriptables qui contiennent une liste de propriétés qui seront affectées à un objet en fonction de l’état actuel. Les thèmes sont également réutilisables et peuvent être affectés sur plusieurs objets d’expérience utilisateur interactive .

Réinitialiser sur la destruction

Les thèmes visuels modifient différentes propriétés sur un GameObject ciblé, en fonction de la classe et du type de moteur de thème sélectionnés. Si Reset On Destroy a la valeur true lorsque le composant interactionnable est détruit, le composant réinitialise toutes les propriétés modifiées des thèmes actifs à leurs valeurs d’origine. Sinon, lorsqu’il est détruit, le composant interagissant laisse toutes les propriétés modifiées comme c’est le cas. Dans ce dernier cas, le dernier état des valeurs persiste, sauf si modifié par un autre composant externe. La valeur par défaut est false.

Profile theams

Événements

Chaque composant interagissant a un événement OnClick qui se déclenche lorsque le composant est simplement sélectionné. Toutefois, l’interaction peut être utilisée pour détecter les événements d’entrée autres que simplement OnClick.

Cliquez sur le bouton Ajouter un événement pour ajouter un nouveau type de définition de récepteur d’événements. Une fois ajouté, sélectionnez le type d’événement souhaité.

Events example)

Il existe différents types de récepteurs d’événements pour répondre à différents types d’entrée. MRTK est fourni avec l’ensemble suivant de récepteurs prêts à l’emploi.

Un récepteur personnalisé peut être créé en créant une nouvelle classe qui s’étend ReceiverBase.

Event Toggle Receiver Example

Exemple d’un récepteur d’événements bascule

Récepteurs interagissants

Le InteractableReceiver composant permet aux événements d’être définis en dehors du composant interactionnable source. InteractableReceiver écoutera un type d’événement filtré déclenché par un autre Interactionable. Si la propriété Interactable n’est pas directement affectée, la propriété Étendue de recherche définit la direction que l’InteractableReceiver écoute pour les événements qui se trouvent sur lui-même, dans un parent ou dans un gameObject enfant.

InteractableReceiverList agit de manière similaire, mais pour une liste d’événements correspondants.

Interactable reciver

Créer des événements personnalisés

Comme les thèmes visuels, les événements peuvent être étendus pour détecter tout modèle d’état ou exposer des fonctionnalités.

Les événements personnalisés peuvent être créés de deux façons principales :

  1. Étendez la ReceiverBase classe pour créer un événement personnalisé qui s’affiche dans la liste déroulante des types d’événements. Un événement Unity est fourni par défaut, mais des événements Unity supplémentaires peuvent être ajoutés ou l’événement peut être défini pour masquer les événements Unity. Cette fonctionnalité permet à un concepteur de travailler avec un ingénieur sur un projet pour créer un événement personnalisé que le concepteur peut configurer dans l’éditeur.

  2. Étendez la ReceiverBaseMonoBehavior classe pour créer un composant d’événement entièrement personnalisé qui peut résider sur l’Interactionable ou un autre objet. Il ReceiverBaseMonoBehavior référencera l’interactionable pour détecter les modifications d’état.

Exemple d’extension ReceiverBase

La CustomInteractablesReceiver classe affiche des informations d’état sur une interaction et est un exemple de création d’un récepteur d’événements personnalisé.

public CustomInteractablesReceiver(UnityEvent ev) : base(ev, "CustomEvent")
{
    HideUnityEvents = true; // hides Unity events in the receiver - meant to be code only
}

Les méthodes suivantes sont utiles pour remplacer/implémenter lors de la création d’un récepteur d’événements personnalisé. ReceiverBase.OnUpdate() est une méthode abstraite qui peut être utilisée pour détecter les modèles d’état/transitions. En outre, les méthodes et ReceiverBase.OnClick() les ReceiverBase.OnVoiceCommand() méthodes sont utiles pour créer une logique d’événement personnalisée lorsque l’interaction est sélectionnée.

public override void OnUpdate(InteractableStates state, Interactable source)
{
    if (state.CurrentState() != lastState)
    {
        // the state has changed, do something new
        lastState = state.CurrentState();
        ...
    }
}

public virtual void OnVoiceCommand(InteractableStates state, Interactable source,
                                    string command, int index = 0, int length = 1)
{
    base.OnVoiceCommand(state, source, command, index, length);
    // voice command called, perform some action
}  

public virtual void OnClick(InteractableStates state,
                            Interactable source,
                            IMixedRealityPointer pointer = null)
{
    base.OnClick(state, source);
    // click called, perform some action
}
Affichage des champs récepteur d’événements personnalisés dans l’inspecteur

Les scripts ReceiverBase utilisent InspectorField des attributs pour exposer des propriétés personnalisées dans l’inspecteur. Voici un exemple de Vector3, une propriété personnalisée avec des informations d’info-bulle et d’étiquette. Cette propriété s’affiche comme configurable dans l’inspecteur lorsqu’un GameObject interagissant est sélectionné et que le type récepteur d’événements associé est ajouté.

[InspectorField(Label = "<Property label>",Tooltip = "<Insert tooltip info>",Type = InspectorField.FieldTypes.Vector3)]
public Vector3 EffectOffset = Vector3.zero;

Guide pratique pour utiliser l’interaction

Création d’un bouton simple

Vous pouvez créer un bouton simple en ajoutant le composant Interactable à un GameObject configuré pour recevoir des événements d’entrée. Il peut avoir un collisionneur sur celui-ci ou sur un enfant pour recevoir une entrée. Si vous utilisez l’interaction avec une interface utilisateur Unity basée sur GameObjects, elle doit être sous Canvas GameObject.

Prenez le bouton une étape plus loin, en créant un profil, en affectant le GameObject lui-même et en créant un nouveau thème. En outre, utilisez l’événement OnClick pour faire quelque chose.

Notes

La création d’un bouton appuyable nécessite le PressableButton composant. En outre, le PhysicalPressEventRouter composant est nécessaire pour entonnoir les événements de presse vers le composant interactable .

Création de boutons bascule et multidimensionnel

Bouton bascule

Pour activer un bouton Bascule, modifiez le Selection Mode champ en type Toggle. Dans la section Profils , un nouveau thème bascule est ajouté pour chaque profil utilisé lorsque l’interaction est activée.

Bien que la SelectionMode valeur Bascule soit définie, la case à cocher IsToggled peut être utilisée pour définir la valeur par défaut du contrôle lors de l’initialisation de l’exécution.

CanSelect signifie que l’interaction peut passer de la sortie à l’autre , tandis que CanDeselect signifie l’inverse.

Profile Toggle Visual Themes Example

Les développeurs peuvent utiliser les interfaces et IsToggled obtenirSetToggled/définir l’état bascule d’une interaction via du code.

// If using SelectionMode = Toggle (i.e Dimensions == 2)

// Make the Interactable selected and toggled on
myInteractable.IsToggled = true;

// Get whether the Interactable is selected or not
bool isSelected = myInteractable.IsToggled;
Activer la collection de boutons

Il est courant d’avoir une liste de boutons bascule où un seul peut être actif à tout moment, également appelé jeu radial ou case d’option, etc.

Utilisez le InteractableToggleCollection composant pour activer cette fonctionnalité. Ce contrôle garantit qu’un seul interactionable est activé à tout moment. Le RadialSet (Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/RadialSet.prefab) est également un excellent point de départ.

Pour créer un groupe de boutons radial personnalisés :

  1. Créer plusieurs gameObjects/boutons interactionnables
  2. Définir chaque interaction avecSelectionMode = Bascule, CanSelect = true et CanDeselect = false
  3. Créer un GameObject parent vide sur tous les interactions et ajouter le composant InteractableToggleCollection
  4. Ajouter toutes les interactions à toggleList sur l’InteractableToggleCollection
  5. Définissez la propriété InteractableToggleCollection.CurrentIndex pour déterminer le bouton sélectionné par défaut au début
Toggle collection

Bouton multidimensionnel

Le mode de sélection multidimensionnel est utilisé pour créer des boutons séquentiels ou un bouton qui comporte plus de deux étapes, comme contrôler la vitesse avec trois valeurs, Fast (1x), Fast (2x) ou Fast (3x).

Avec des dimensions représentant une valeur numérique, jusqu’à 9 thèmes peuvent être ajoutés pour contrôler l’étiquette de texte ou la texture du bouton pour chaque paramètre de vitesse, à l’aide d’un thème différent pour chaque étape.

Chaque événement de clic avance le DimensionIndex 1 au moment de l’exécution jusqu’à ce que la Dimensions valeur soit atteinte. Ensuite, le cycle est réinitialisé à 0.

Multi-Dimensional profile example

Les développeurs peuvent évaluer la DimensionIndex dimension à déterminer quelle dimension est actuellement active.

// If using SelectionMode = Multi-dimension (i.e Dimensions >= 3)

//Access the current DimensionIndex
int currentDimension = myInteractable.CurrentDimension;

//Set the current DimensionIndex to 2
myInteractable.CurrentDimension = 2;

// Promote Dimension to next level
myInteractable.IncreaseDimension();

Créer des interactions au moment de l’exécution

L’interaction peut être facilement ajoutée à n’importe quel GameObject au moment de l’exécution. L’exemple suivant montre comment affecter un profil avec un thème visuel.

var interactableObject = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
var interactable = interactableObject.AddComponent<Interactable>();

// Get the default configuration for the Theme engine InteractableColorTheme
var newThemeType = ThemeDefinition.GetDefaultThemeDefinition<InteractableColorTheme>().Value;

// Define a color for every state in our Default Interactable States
newThemeType.StateProperties[0].Values = new List<ThemePropertyValue>()
{
    new ThemePropertyValue() { Color = Color.black},  // Default
    new ThemePropertyValue() { Color = Color.black}, // Focus
    new ThemePropertyValue() { Color = Random.ColorHSV()},   // Pressed
    new ThemePropertyValue() { Color = Color.black},   // Disabled
};

interactable.Profiles = new List<InteractableProfileItem>()
{
    new InteractableProfileItem()
    {
        Themes = new List<Theme>()
        {
            Interactable.GetDefaultThemeAsset(new List<ThemeDefinition>() { newThemeType })
        },
        Target = interactableObject,
    },
};

// Force the Interactable to be clicked
interactable.TriggerOnClick()

Événements interagissants via du code

Vous pouvez ajouter une action à l’événement de base Interactable.OnClick via du code avec l’exemple suivant.

public static void AddOnClick(Interactable interactable)
{
    interactable.OnClick.AddListener(() => Debug.Log("Interactable clicked"));
}

Utilisez la Interactable.AddReceiver<T>() fonction pour ajouter dynamiquement des récepteurs d’événements au moment de l’exécution.

L’exemple de code ci-dessous montre comment ajouter un InteractableOnFocusReceiver, qui écoute l’entrée/la sortie du focus, et définir le code d’action à effectuer lorsque les instances d’événement se déclenchent.

public static void AddFocusEvents(Interactable interactable)
{
    var onFocusReceiver = interactable.AddReceiver<InteractableOnFocusReceiver>();

    onFocusReceiver.OnFocusOn.AddListener(() => Debug.Log("Focus on"));
    onFocusReceiver.OnFocusOff.AddListener(() => Debug.Log("Focus off"));
}

L’exemple de code ci-dessous montre comment ajouter un interactableOnToggleReceiver, qui écoute les transitions d’état sélectionnées/désélectionnées sur les interactions pouvant être activées par bascule, et définit en outre le code d’action à effectuer lorsque les instances d’événement se déclenchent.

public static void AddToggleEvents(Interactable interactable)
{
    var toggleReceiver = interactable.AddReceiver<InteractableOnToggleReceiver>();

    // Make the interactable have toggle capability, from code.
    // In the gui editor it's much easier
    interactable.Dimensions = 2;
    interactable.CanSelect = true;
    interactable.CanDeselect  = true;

    toggleReceiver.OnSelect.AddListener(() => Debug.Log("Toggle selected"));
    toggleReceiver.OnDeselect.AddListener(() => Debug.Log("Toggle un-selected"));
}

Voir aussi