Interagierbar – MRTK2

Interaktionsfähig

Die Interactable Komponente ist ein All-in-One-Container, um jedes Objekt einfach zu interagieren und auf Eingaben zu reagieren. Interaktiv fungiert als Catch-All für alle Arten von Eingaben, einschließlich Toucheingaben, Handstrahlen, Sprache usw. und leiten diese Interaktionen in Ereignisse und visuelle Designantworten . Diese Komponente bietet eine einfache Möglichkeit, Schaltflächen zu erstellen, die Farbe für Objekte mit Fokus zu ändern und vieles mehr.

Konfigurieren von Interagierbarem

Die Komponente ermöglicht drei primäre Konfigurationsabschnitte:

  1. Allgemeine Eingabekonfiguration
  2. Visuelle Designs , die auf mehrere GameObjects ausgerichtet sind
  3. Ereignishandler

Allgemeine Eingabeeinstellungen

Allgemeine interaktionsfähige Einstellungen

Status

States ist ein ScriptableObject-Parameter , der die Interaktionsphasen definiert, z. B. drücken oder beobachtet, für Interagierbare Profile und visuelle Designs.

DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) wird sofort mit MRTK ausgeliefert und ist der Standardparameter für Interaktive Komponenten.

SkriptableObject-Beispiel für Zustände im Inspektor

Das DefaultInteractableStates-Objekt enthält vier Zustände und verwendet die InteractableStates Zustandsmodellimplementierung.

  • Standard: Es geschieht nichts, dies ist der isoliertste Basiszustand.

  • Fokus: Auf das Objekt wird gezeigt. Dies ist ein einzelner Zustand, es sind derzeit keine anderen Zustände festgelegt, aber es wird der Rang "Standard" übersteigen.

  • Drücken: Auf das Objekt wird gezeigt, und eine Taste oder Hand wird gedrückt. Der Status "Press out" rangiert "Standard" und "Fokus". Dieser Zustand wird auch als Fallback auf Physisches Drücken festgelegt.

  • Deaktiviert: Die Schaltfläche sollte nicht interaktiv sein, und visuelles Feedback informiert den Benutzer darüber, ob diese Schaltfläche aus irgendeinem Grund derzeit nicht verwendet werden kann. Theoretisch könnte der deaktivierte Zustand alle anderen Zustände enthalten, aber wenn Aktiviert deaktiviert ist, übertrumpft der deaktivierte Zustand alle anderen Zustände.

Abhängig von der Reihenfolge in der Liste wird dem Zustand ein Bitwert (#) zugewiesen.

Hinweis

Es wird allgemein empfohlen, beim Erstellen interaktiver Komponenten defaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) zu verwenden.

Es stehen jedoch 17 Interagierbare Zustände zur Verfügung, die zum Steuern von Designs verwendet werden können, obwohl einige von anderen Komponenten gesteuert werden sollen. Hier finden Sie eine Liste derjenigen mit integrierter Funktionalität.

  • Besucht: Auf das Interagierbare wurde geklickt.
  • Umschalten: Die Schaltfläche befindet sich in einem umschaltbaren Zustand, oder der Dimensionsindex ist eine ungerade Zahl.
  • Geste: Die Hand oder der Controller wurde gedrückt und hat sich von der ursprünglichen Position entfernt.
  • VoiceCommand: Ein Sprachbefehl wurde verwendet, um das Interaktive auszulösen.
  • PhysicalTouch: Eine Toucheingabe wird derzeit erkannt, verwenden Sie NearInteractionTouchable zum Aktivieren.
  • Grab: Eine Hand greift derzeit in den Begrenzungen des Objekts, verwenden Sie NearInteractionGrabbable , um zu aktivieren

Aktiviert

Schaltet um, ob ein Interaktives aktiviert wird oder nicht. Dies entspricht dem Interactable.IsEnabled im Code.

Die aktivierte Eigenschaft von Interactable unterscheidet sich von der aktivierten Eigenschaft, die über GameObject/Component (d. h. SetActive usw.) konfiguriert wurde. Wenn Sie gameObject oder Interactable MonoBehaviour deaktivieren, kann alles in der Klasse ausgeführt werden, einschließlich Eingaben, visuellen Designs, Ereignissen usw. Die Deaktivierung über Interactable.IsEnabled deaktiviert die meisten Eingabebehandlungen, und die zugehörigen Eingabezustände werden zurückgesetzt. Die Klasse führt jedoch weiterhin jeden Frame aus und empfängt Eingabeereignisse, die ignoriert werden. Dies ist nützlich für die Anzeige des Interaktiven in einem deaktivierten Zustand, der über visual Designs erfolgen kann. Ein typisches Beispiel hierfür wäre eine Übermittlungsschaltfläche, die darauf wartet, dass alle erforderlichen Eingabefelder abgeschlossen sind.

Eingabeaktionen

Wählen Sie die Eingabeaktion aus dem Eingabekonfigurations- oder Controllerzuordnungsprofil aus, auf das die interaktive Komponente reagieren soll.

Diese Eigenschaft kann zur Laufzeit im Code über Interactable.InputActionkonfiguriert werden.

IsGlobal

Wenn true, wird die Komponente als globaler Eingabelistener für die ausgewählte Eingabeaktion markiert. Das Standardverhalten ist false, wodurch die Eingabe nur auf diesen Interagierbaren Collider/GameObject beschränkt wird.

Diese Eigenschaft kann zur Laufzeit im Code über Interactable.IsGlobalkonfiguriert werden.

Sprachbefehl

Sprachbefehl aus dem MRTK-Sprachbefehlsprofil, um ein OnClick-Ereignis für die Sprachinteraktion auszulösen.

Diese Eigenschaft kann zur Laufzeit im Code über Interactable.VoiceCommandkonfiguriert werden.

Erfordert Fokus

Wenn true, aktiviert der Sprachbefehl den Interaktiven nur, wenn er bereits über den Fokus eines Zeigers verfügt. Wenn false, fungiert der Interaktive als globaler Listener für den ausgewählten Sprachbefehl. Das Standardverhalten ist wahr, da mehrere globale Sprachlistener in einer Szene schwierig zu organisieren sein können.

Diese Eigenschaft kann zur Laufzeit im Code über Interactable.VoiceRequiresFocuskonfiguriert werden.

Auswahlmodus

Diese Eigenschaft definiert die Auswahllogik. Wenn auf ein Interagierbares geklickt wird, wird eine nächste Dimensionsebene durchlaufen. Dimensionen ähneln dem Rang und definieren einen Zustand außerhalb von Eingaben (z. B. Fokus, Drücken usw.). Sie sind nützlich zum Definieren von Umschaltzuständen oder anderen mehrstufigen Zuständen, die einer Schaltfläche zugeordnet sind. Die aktuelle Dimensionsebene wird von Interactable.DimensionIndexnachverfolgt.

Die verfügbaren Auswahlmodi sind:

  • Schaltfläche - Dimensionen = 1, einfach anklickbar Interagierbar
  • Umschalten - Dimensionen = 2, Interagierbare Alternativen zwischen dem Aus-Zustand/
  • Mehrdimensionale - Dimensionen>= 3, jeder Klick erhöht die aktuelle Dimensionsebene + 1. Nützlich zum Definieren eines Schaltflächenzustands für eine Liste usw.

Interagierbar ermöglicht auch die Definition mehrerer Designs pro Dimension. Wenn beispielsweise SelectionMode=Umschalten verwendet wird, kann ein Design angewendet werden, wenn das Interagierbaredeaktiviert wird, und ein anderes Design, wenn die Komponente ausgewählt wird.

Der aktuelle Auswahlmodus kann zur Laufzeit über Interactable.ButtonModeabgefragt werden. Das Aktualisieren des Modus zur Laufzeit kann erreicht werden, indem die Interactable.Dimensions -Eigenschaft so festgelegt wird, dass sie der gewünschten Funktionalität entspricht. Darüber hinaus kann über Interactable.CurrentDimensionauf die aktuelle Dimension zugegriffen werden, die für umschaltbare und mehrdimensionale Modi nützlich ist.

Interagierbare Profile

Profile sind Elemente, die eine Beziehung zwischen einem GameObject und einem visuellen Design erstellen. Das Profil definiert, welche Inhalte bei einer Zustandsänderung von einem Design bearbeitet werden.

Designs funktionieren sehr wie Materialien. Es handelt sich um skriptfähige Objekte, die eine Liste von Eigenschaften enthalten, die einem Objekt basierend auf dem aktuellen Zustand zugewiesen werden. Designs sind auch wiederverwendbar und können über mehrere interaktive UX-Objekte hinweg zugewiesen werden.

Zurücksetzen bei Zerstörung

Visuelle Designs ändern verschiedene Eigenschaften für ein zielorientiertes GameObject, abhängig von der Klasse und dem Typ der ausgewählten Design-Engine. Wenn Reset On Destroy true ist, wenn die Interaktivierbare Komponente zerstört wird, setzt die Komponente alle geänderten Eigenschaften von aktiven Designs auf ihre ursprünglichen Werte zurück. Andernfalls belässt die interagierbare Komponente beim Zerstören alle geänderten Eigenschaften unverändert. In diesem letzteren Fall bleibt der letzte Zustand der Werte bestehen, es sei denn, es wird von einer anderen externen Komponente geändert. Die Standardeinstellung ist „false“.

Profil theams

Ereignisse

Jede interagierbare Komponente verfügt über ein OnClick-Ereignis , das ausgelöst wird, wenn die Komponente einfach ausgewählt wird. Interactable kann jedoch verwendet werden, um andere Eingabeereignisse als nur OnClick zu erkennen.

Klicken Sie auf die Schaltfläche Ereignis hinzufügen , um einen neuen Typ der Ereignisempfängerdefinition hinzuzufügen. Wählen Sie nach dem Hinzufügen den gewünschten Ereignistyp aus.

Ereignisbeispiel)

Es gibt verschiedene Arten von Ereignisempfängern, um auf verschiedene Arten von Eingaben zu reagieren. MRTK wird sofort mit den folgenden Empfängern ausgeliefert.

Ein benutzerdefinierter Empfänger kann erstellt werden, indem Eine neue Klasse erstellt wird, die erweitert ReceiverBase.

Ereignis-Umschaltempfänger (Beispiel)

Beispiel für einen Umschaltereignisempfänger

Interaktionsfähige Empfänger

Die InteractableReceiver -Komponente ermöglicht die Definition von Ereignissen außerhalb der interagierbaren Quellkomponente. Der InteractableReceiver lauscht auf einen gefilterten Ereignistyp, der von einem anderen Interactable ausgelöst wird. Wenn die Interactable-Eigenschaft nicht direkt zugewiesen wird, definiert die Search Scope-Eigenschaft die Richtung, in der der InteractableReceiver auf Ereignisse lauscht, die sich entweder auf sich selbst, in einem übergeordneten Objekt oder in einem untergeordneten GameObject befinden.

InteractableReceiverList verhält sich ähnlich, aber für eine Liste übereinstimmenden Ereignisse.

Interagierbarer Reiver

Erstellen benutzerdefinierter Ereignisse

Wie visual Designs können Ereignisse erweitert werden, um ein beliebiges Zustandsmuster zu erkennen oder Funktionen verfügbar zu machen.

Benutzerdefinierte Ereignisse können auf zwei Standard Arten erstellt werden:

  1. Erweitern Sie die ReceiverBase -Klasse, um ein benutzerdefiniertes Ereignis zu erstellen, das in der Dropdownliste der Ereignistypen angezeigt wird. Standardmäßig wird ein Unity-Ereignis bereitgestellt, aber es können zusätzliche Unity-Ereignisse hinzugefügt werden, oder das Ereignis kann so festgelegt werden, dass Unity-Ereignisse ausgeblendet werden. Diese Funktion ermöglicht es einem Designer, mit einem Techniker an einem Projekt zusammenzuarbeiten, um ein benutzerdefiniertes Ereignis zu erstellen, das der Designer im Editor einrichten kann.

  2. Erweitern Sie die ReceiverBaseMonoBehavior -Klasse, um eine vollständig benutzerdefinierte Ereigniskomponente zu erstellen, die sich auf dem Interactable-Objekt oder einem anderen Objekt befinden kann. Der ReceiverBaseMonoBehavior verweist auf Interagierbare , um Zustandsänderungen zu erkennen.

Beispiel für das Erweitern ReceiverBase

Die CustomInteractablesReceiver -Klasse zeigt status Informationen zu einem Interagierbaren an und ist ein Beispiel für das Erstellen eines benutzerdefinierten Ereignisempfängers.

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

Die folgenden Methoden sind nützlich, um beim Erstellen eines benutzerdefinierten Ereignisempfängers zu überschreiben bzw. zu implementieren. ReceiverBase.OnUpdate() ist eine abstrakte Methode, die verwendet werden kann, um Zustandsmuster/-übergänge zu erkennen. Darüber hinaus sind die ReceiverBase.OnVoiceCommand() Methoden und ReceiverBase.OnClick() nützlich, um benutzerdefinierte Ereignislogik zu erstellen, wenn interagierbar ausgewählt ist.

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
}
Anzeigen benutzerdefinierter Ereignisempfängerfelder im Inspektor

ReceiverBase-Skripts verwenden InspectorField Attribute, um benutzerdefinierte Eigenschaften im Inspektor verfügbar zu machen. Hier sehen Sie ein Beispiel für Vector3, eine benutzerdefinierte Eigenschaft mit QuickInfo und Beschriftungsinformationen. Diese Eigenschaft wird im Inspektor als konfigurierbar angezeigt, wenn ein interagierbares GameObject ausgewählt ist und der zugehörige Ereignisempfängertyp hinzugefügt wird.

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

Verwenden von Interagierbarem

Erstellen einer einfachen Schaltfläche

Sie können eine einfache Schaltfläche erstellen, indem Sie die Interagierbare Komponente zu einem GameObject hinzufügen, das zum Empfangen von Eingabeereignissen konfiguriert ist. Es kann einen Collider darauf oder auf einem untergeordneten Element enthalten, um Eingaben zu empfangen. Wenn Sie Interactable mit einer Unity-Benutzeroberfläche basierenden GameObjects verwenden, sollte es sich unter dem Canvas GameObject befinden.

Gehen Sie mit der Schaltfläche einen Schritt weiter, indem Sie ein neues Profil erstellen, das GameObject selbst zuweisen und ein neues Design erstellen. Verwenden Sie außerdem das OnClick-Ereignis , um etwas zu bewirken.

Hinweis

Damit eine Schaltfläche gedrückt werden kann , ist die PressableButton Komponente erforderlich. Darüber hinaus wird die PhysicalPressEventRouter Komponente benötigt, um Druckereignisse an die Interaktive Komponente zu leiten.

Erstellen von Umschalt- und Mehrdimensionsschaltflächen

Umschalter

Um eine Schaltfläche umschalten zu können, ändern Sie das Selection Mode Feld in den Typ Toggle. Im Abschnitt Profile wird ein neues umschaltbares Design für jedes Profil hinzugefügt, das verwendet wird, wenn interagierbar aktiviert ist.

Während auf SelectionMode Umschalten festgelegt ist, kann das Kontrollkästchen IsToggled verwendet werden, um den Standardwert des Steuerelements bei der Laufzeitinitialisierung festzulegen.

CanSelect bedeutet, dass das Interaktive von aus nach ein wechseln kann, während CanDeselect die Inverse bedeutet.

Beispiel für visuelle Designs zum Umschalten des Profils

Entwickler können die SetToggled Schnittstellen und IsToggled verwenden, um den Umschaltzustand eines Interagierbaren über Code abzurufen bzw. festzulegen.

// 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;
Schaltflächensammlung umschalten

Es ist üblich, eine Liste von Umschalttasten zu haben, in denen nur eine zu einem bestimmten Zeitpunkt aktiv sein kann, auch bekannt als Radialsatz oder Optionsfelder usw.

Verwenden Sie die InteractableToggleCollection Komponente, um diese Funktionalität zu aktivieren. Dieses Steuerelement stellt sicher, dass zu einem bestimmten Zeitpunkt nur ein Interagierbares aktiviert wird. Das RadialSet (Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/RadialSet.prefab) ist ebenfalls ein hervorragender Ausgangspunkt.

So erstellen Sie eine benutzerdefinierte radiale Schaltflächengruppe:

  1. Erstellen mehrerer interagierbarer GameObjects/Schaltflächen
  2. Legen Sie jede Interaktion mit SelectionMode = Umschalten, CanSelect = true und CanDeselect = false fest.
  3. Erstellen Sie ein leeres übergeordnetes GameObject für alle Interactables, und fügen Sie die InteractableToggleCollection-Komponente hinzu.
  4. Hinzufügen aller Interactables zur ToggleList in der InteractableToggleCollection
  5. Legen Sie die InteractableToggleCollection.CurrentIndex-Eigenschaft fest, um zu bestimmen, welche Schaltfläche standardmäßig beim Start ausgewählt ist.
Sammlung umschalten

Mehrdimensionale Schaltfläche

Der Mehrdimensionale Auswahlmodus wird verwendet, um sequenzielle Schaltflächen oder eine Schaltfläche mit mehr als zwei Schritten zu erstellen, z. B. die Steuerung der Geschwindigkeit mit drei Werten, Fast (1x), Faster (2x) oder Fastest (3x).

Da Dimensionen ein numerischer Wert sind, können bis zu 9 Designs hinzugefügt werden, um die Textbezeichnung oder Textur der Schaltfläche für jede Geschwindigkeitseinstellung zu steuern, wobei für jeden Schritt ein anderes Design verwendet wird.

Jedes Klickereignis wird zur DimensionIndex Laufzeit um 1 erweitert, bis der Dimensions Wert erreicht ist. Anschließend wird der Zyklus auf 0 zurückgesetzt.

Beispiel für ein mehrdimensionales Profil

Entwickler können die DimensionIndex bewerten, um zu bestimmen, welche Dimension derzeit aktiv ist.

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

Erstellen von Interagierbar zur Laufzeit

Interagierbar kann zur Laufzeit einfach zu jedem GameObject hinzugefügt werden. Im folgenden Beispiel wird veranschaulicht, wie Sie ein Profil mit einem visuellen Design zuweisen.

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

Interagierbare Ereignisse über Code

Mit dem folgenden Beispiel kann dem Basisereignis Interactable.OnClick über Code eine Aktion hinzugefügt werden.

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

Verwenden Sie die Interactable.AddReceiver<T>() Funktion, um Ereignisempfänger dynamisch zur Laufzeit hinzuzufügen.

Der folgende Beispielcode veranschaulicht, wie Sie einen InteractableOnFocusReceiver hinzufügen, der auf die Fokuseingabe/-beendigung lauscht, und darüber hinaus Aktionscode definiert, der ausgeführt werden soll, wenn die Ereignisinstanzen ausgelöst werden.

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

Der folgende Beispielcode veranschaulicht, wie ein InteractableOnToggleReceiver hinzugefügt wird, der auf ausgewählte/deaktivierte Zustandsübergänge für umschaltbare Interactables lauscht und darüber hinaus Aktionscode definiert, der ausgeführt werden soll, wenn die Ereignisinstanzen ausgelöst werden.

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

Weitere Informationen