Interactable: MRTK2
El Interactable
componente es un contenedor todo en uno para que cualquier objeto pueda interactuar fácilmente y responder a la entrada. Interactable actúa como un catch-all para todos los tipos de entrada, incluidos los toques, los rayos de mano, la voz, etc. y embudo de estas interacciones en eventos y respuestas de temas visuales . Este componente proporciona una manera sencilla de hacer botones, cambiar el color de los objetos con foco y mucho más.
Cómo configurar Interactable
El componente permite tres secciones principales de configuración:
- Configuración de entrada general
- Temas visuales dirigidos a varios GameObjects
- Controladores de eventos
Configuración de entrada general
States
States es un parámetro ScriptableObject que define las fases de interacción, como presionar o observar, para perfiles interactivos y temas visuales.
DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) se suministra con MRTK de fábrica y es el parámetro predeterminado para los componentes interactables.
El recurso DefaultInteractableStates contiene cuatro estados y utiliza la implementación del InteractableStates
modelo de estado.
Valor predeterminado: No sucede nada, este es el estado base más aislado.
Foco: el objeto al que se apunta. Se trata de un solo estado, no hay ningún otro estado establecido actualmente, pero se clasificará como Predeterminado.
Presionar: el objeto se está apuntando y un botón o una mano está presionando. El estado Press out clasifica Default y Focus. Este estado también se establecerá como reserva en La prensa física.
Deshabilitado: el botón no debe ser interactivo y los comentarios visuales permitirán al usuario saber si por alguna razón este botón no se puede usar en este momento. En teoría, el estado deshabilitado podría contener todos los demás estados, pero cuando Enabled está desactivado, el estado Disabled supera todos los demás estados.
Se asigna un valor de bit (#) al estado en función del orden de la lista.
Nota:
Por lo general, se recomienda usar DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) al crear componentes interactables .
Sin embargo, hay 17 estados interactables disponibles que se pueden usar para controlar temas, aunque algunos están diseñados para ser controlados por otros componentes. Esta es una lista de las que tienen funcionalidad integrada.
- Visitado: se ha realizado clic en interactable.
- Alternado: el botón está en un estado de alternancia o el índice de dimensión es un número impar.
- Gesto: se presionó la mano o el controlador y se ha movido de la posición original.
- VoiceCommand: se usó un comando de voz para desencadenar interactable.
- PhysicalTouch: se detecta actualmente una entrada táctil, que se usa
NearInteractionTouchable
para habilitar. - Agarre: una mano se está agarrando actualmente en los límites del objeto, use
NearInteractionGrabbable
para habilitar
Enabled
Alterna si un objeto Interactable se iniciará habilitado o no. Esto corresponde al elemento en el Interactable.IsEnabled
código.
La propiedad habilitada de un objeto Interactable es diferente de la propiedad habilitada configurada a través de GameObject/Component (es decir, SetActive, etc.). Deshabilitar GameObject o MonoBehaviour interactivo deshabilitará todo lo que hay en la clase para que se ejecute, incluidos los datos de entrada, los temas visuales, los eventos, etc. La deshabilitación mediante Interactable.IsEnabled
deshabilitará la mayoría del control de entrada y restablecerá los estados de entrada relacionados. Sin embargo, la clase seguirá ejecutando cada fotograma y recibirá eventos de entrada que se omitirán. Esto resulta útil para mostrar el objeto Interactable en un estado deshabilitado que se puede realizar a través de Temas visuales. Un ejemplo típico de esto sería un botón enviar esperando a que se completen todos los campos de entrada necesarios.
Acciones de entrada
Seleccione la acción de entrada en el perfil de asignación de controlador o configuración de entrada al que debe reaccionar el componente interactable .
Esta propiedad se puede configurar en tiempo de ejecución en el código a través de Interactable.InputAction
.
IsGlobal
Si es true, esto marcará el componente como un agente de escucha de entrada global para la acción de entrada seleccionada. El comportamiento predeterminado es false, lo que restringirá la entrada solo a este colisionador interactable o GameObject.
Esta propiedad se puede configurar en tiempo de ejecución en el código a través de Interactable.IsGlobal
.
Comando voz
Comando de voz, desde el perfil de comandos de voz de MRTK, para desencadenar un evento OnClick para la interacción de voz.
Esta propiedad se puede configurar en tiempo de ejecución en el código a través de Interactable.VoiceCommand
.
Requiere el foco
Si es true, el comando de voz solo activará interactable si y solo si ya tiene el foco desde un puntero. Si es false, el objeto Interactable actuará como agente de escucha global para el comando de voz seleccionado. El comportamiento predeterminado es true, ya que varios agentes de escucha de voz globales pueden ser difíciles de organizar en una escena.
Esta propiedad se puede configurar en tiempo de ejecución en el código a través de Interactable.VoiceRequiresFocus
.
Modo de selección
Esta propiedad define la lógica de selección. Cuando se hace clic en un objeto Interactable , itera en un siguiente nivel de dimensión .
Las dimensiones son similares a la clasificación y definen un estado fuera de las entradas (es decir, el foco, la presión, etc.). Son útiles para definir estados de alternancia u otros estados de rango múltiple asociados a un botón. Se realiza un seguimiento del nivel de dimensión actual mediante Interactable.DimensionIndex
.
Los modos de selección disponibles son:
- Botón - Dimensiones = 1, fácil de hacer clic en Interactable
- Alternar - Dimensiones = 2, alternativas interactables entre el/ estadodesactivado
- Varias dimensiones - Dimensiones>= 3, cada clic aumenta el nivel de dimensión actual + 1. Resulta útil para definir un estado de botón en una lista, etc.
Interactable también permite definir varios temas por dimensión. Por ejemplo, cuando SelectionMode=Toggle, se puede aplicar un tema cuando se deseleccionaInteractable y se aplique otro tema cuando se seleccione el componente.
El modo de selección actual se puede consultar en tiempo de ejecución a través de Interactable.ButtonMode
. La actualización del modo en tiempo de ejecución se puede lograr estableciendo la Interactable.Dimensions
propiedad para que coincida con la funcionalidad deseada. Además, se puede acceder a la dimensión actual, útil para los modos Alternar y Multidimensional , a través de Interactable.CurrentDimension
.
Perfiles interactivos
Los perfiles son elementos que crean una relación entre un GameObject y un tema visual. El perfil define qué contenido manipulará un tema cuando se produzca un cambio de estado.
Los temas funcionan mucho como materiales. Son objetos que admiten scripts que contienen una lista de propiedades que se asignarán a un objeto en función del estado actual. Los temas también se pueden volver a usar y se pueden asignar a través de varios objetos de experiencia de usuario interactivos .
Restablecer al destruir
Los temas visuales modifican varias propiedades en un GameObject de destino, dependiendo de la clase y el tipo de motor de temas seleccionado. Si Reset On Destroy es true cuando se destruye el componente Interactable, el componente restablecerá todas las propiedades modificadas de los temas activos a sus valores originales. De lo contrario, cuando se destruye, el componente interactable dejará las propiedades modificadas tal como están. En este último caso, el último estado de los valores se conservará a menos que otro componente externo modifique. El valor predeterminado es false.
Eventos
Cada componente interactable tiene un evento OnClick que se desencadena cuando el componente se selecciona simplemente. Sin embargo, se puede usar Interactable para detectar eventos de entrada distintos de solo OnClick.
Haga clic en el botón Agregar evento para agregar un nuevo tipo de definición del receptor de eventos. Una vez agregado, seleccione el tipo de evento deseado.
)
Hay diferentes tipos de receptores de eventos para responder a diferentes tipos de entrada. MRTK incluye el siguiente conjunto de receptores listos para usar.
InteractableAudioReceiver
InteractableOnClickReceiver
InteractableOnFocusReceiver
InteractableOnGrabReceiver
InteractableOnHoldReceiver
InteractableOnPressReceiver
InteractableOnToggleReceiver
InteractableOnTouchReceiver
Se puede crear un receptor personalizado mediante la creación de una nueva clase que extiende ReceiverBase
.
Ejemplo de un receptor de eventos toggle
Receptores interactivos
El InteractableReceiver
componente permite definir eventos fuera del componente interactable de origen.
InteractableReceiver escuchará un tipo de evento filtrado desencadenado por otro objeto Interactable. Si la propiedad Interactable no está asignada directamente, la propiedad Ámbito de búsqueda define la dirección en la que InteractableReceiver escucha eventos que están en sí, en un elemento primario o en un gameObject secundario.
InteractableReceiverList
actúa de forma similar, pero para una lista de eventos coincidentes.
Creación de eventos personalizados
Al igual que los temas visuales, los eventos se pueden ampliar para detectar cualquier patrón de estado o exponer la funcionalidad.
Los eventos personalizados se pueden crear de dos maneras principales:
Extienda la
ReceiverBase
clase para crear un evento personalizado que se mostrará en la lista desplegable de tipos de eventos. De forma predeterminada, se proporciona un evento de Unity, pero se pueden agregar eventos adicionales de Unity o el evento se puede establecer para ocultar eventos de Unity. Esta funcionalidad permite a un diseñador trabajar con un ingeniero en un proyecto para crear un evento personalizado que el diseñador pueda configurar en el editor.Extienda la
ReceiverBaseMonoBehavior
clase para crear un componente de eventos completamente personalizado que pueda residir en el objeto Interactable u otro objeto. HaráReceiverBaseMonoBehavior
referencia al objeto Interactable para detectar cambios de estado.
Ejemplo de extensión ReceiverBase
La CustomInteractablesReceiver
clase muestra información de estado sobre un objeto Interactable y es un ejemplo de cómo crear un receptor de eventos personalizado.
public CustomInteractablesReceiver(UnityEvent ev) : base(ev, "CustomEvent")
{
HideUnityEvents = true; // hides Unity events in the receiver - meant to be code only
}
Los métodos siguientes son útiles para invalidar o implementar al crear un receptor de eventos personalizado.
ReceiverBase.OnUpdate()
es un método abstracto que se puede usar para detectar patrones de estado o transiciones. Además, los ReceiverBase.OnVoiceCommand()
métodos y ReceiverBase.OnClick()
son útiles para crear lógica de eventos personalizados cuando se selecciona interactable .
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
}
Mostrar campos de receptor de eventos personalizados en el inspector
Los scripts receiverBase usan InspectorField
atributos para exponer propiedades personalizadas en el inspector. Este es un ejemplo de Vector3, una propiedad personalizada con información sobre herramientas e información de etiquetas. Esta propiedad se mostrará como configurable en el inspector cuando se seleccione un GameObject interactivo y tenga agregado el tipo receptor de eventos asociado.
[InspectorField(Label = "<Property label>",Tooltip = "<Insert tooltip info>",Type = InspectorField.FieldTypes.Vector3)]
public Vector3 EffectOffset = Vector3.zero;
Cómo usar Interactable
Creación de un botón sencillo
Se puede crear un botón simple agregando el componente Interactable a un GameObject configurado para recibir eventos de entrada. Puede tener un colisionador en él o en un elemento secundario para recibir la entrada. Si usa Interactable con gameObjects basado en la interfaz de usuario de Unity, debe estar en Canvas GameObject.
Tome el botón un paso más allá, creando un nuevo perfil, asignando el propio GameObject y creando un nuevo tema. Además, use el evento OnClick para hacer que suceda algo.
Nota:
Hacer que un botón se pueda presionar requiere el PressableButton
componente. Además, el PhysicalPressEventRouter
componente es necesario para embudo de eventos de prensa en el componente Interactable .
Crear botones de alternancia y de varias dimensiones
Botón de alternancia
Para hacer que un botón Se pueda alternar, cambie el Selection Mode
campo por escribir Toggle
. En la sección Perfiles , se agrega un nuevo tema alternado para cada perfil que se usa cuando se activa la opción Interactable .
Mientras se establece en SelectionMode
Alternancia, se puede usar la casilla IsToggled para establecer el valor predeterminado del control en la inicialización en tiempo de ejecución.
CanSelect significa que interactable puede pasar de desactivado a activado mientras que CanDeselect significa el inverso.
Los desarrolladores pueden usar las SetToggled
interfaces y IsToggled
para obtener o establecer el estado de alternancia de un objeto Interactable a través del código.
// 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;
Alternar colección de botones
Es habitual tener una lista de botones de alternancia donde solo uno puede estar activo en un momento dado, también conocido como un conjunto radial o botones de radio, etc.
Use el InteractableToggleCollection
componente para habilitar esta funcionalidad. Este control garantiza que solo se active un objeto Interactable en un momento dado.
RadialSet (Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/RadialSet.prefab) también es un excelente punto de partida de fábrica.
Para crear un grupo de botones radiales personalizado:
- Crear varios gameObjects o botones interactivos
- Establecer cada objeto Interactable con SelectionMode = Toggle, CanSelect = true y CanDeselect = false
- Cree un elemento GameObject primario vacío en todos los elementos Interactables y agregue el componente InteractableToggleCollection .
- Agregar todos los objetos Interactables a ToggleList en InteractableToggleCollection
- Establezca la propiedad InteractableToggleCollection.CurrentIndex para determinar qué botón está seleccionado de forma predeterminada al principio.
Botón multidimensional
El modo de selección multidimensional se usa para crear botones secuenciales o un botón que tenga más de dos pasos, como controlar la velocidad con tres valores, Rápido (1x), Más rápido (2x) o Rápido (3x).
Con las dimensiones que son un valor numérico, se pueden agregar hasta 9 temas para controlar la etiqueta de texto o la textura del botón para cada configuración de velocidad, usando un tema diferente para cada paso.
Cada evento de clic avanzará en DimensionIndex
1 en tiempo de ejecución hasta que se alcance el Dimensions
valor. A continuación, el ciclo se restablecerá a 0.
Los desarrolladores pueden evaluar para DimensionIndex
determinar qué dimensión está activa actualmente.
// 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();
Creación de una interacción en tiempo de ejecución
La interacción se puede agregar fácilmente a cualquier GameObject en tiempo de ejecución. En el ejemplo siguiente se muestra cómo asignar un perfil con un tema visual.
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()
Eventos interactivos a través del código
Puede agregar una acción al evento base Interactable.OnClick
mediante código con el ejemplo siguiente.
public static void AddOnClick(Interactable interactable)
{
interactable.OnClick.AddListener(() => Debug.Log("Interactable clicked"));
}
Use la Interactable.AddReceiver<T>()
función para agregar receptores de eventos dinámicamente en tiempo de ejecución.
En el código de ejemplo siguiente se muestra cómo agregar un objeto InteractableOnFocusReceiver, que escucha la entrada y salida del foco y, además, define el código de acción para realizar cuando se activan las instancias de evento.
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"));
}
En el código de ejemplo siguiente se muestra cómo agregar un interactableOnToggleReceiver, que escucha las transiciones de estado seleccionadas o deseleccionada en los interactables con alternancia y, además, define el código de acción que se realizará cuando se activen las instancias de evento.
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"));
}