Interacionável — MRTK2
O Interactable
componente é um contentor tudo-em-um para tornar qualquer objeto facilmente interagivel e reativo à entrada. O interactável funciona como um catch-all para todos os tipos de entrada, incluindo toque, raios de mão, voz, etc. e funilize estas interações em eventos e respostas de temas visuais . Este componente fornece uma forma fácil de criar botões, alterar a cor nos objetos com foco e muito mais.
Como configurar o Interactable
O componente permite três secções primárias de configuração:
- Configuração de entrada geral
- Temas Visuais direcionados para vários GameObjects
- Processadores de eventos
Definições de entrada gerais
Estados
States é um parâmetro ScriptableObject que define as fases de interação, como premir ou observar, para Perfis Interagiveis e Temas Visuais.
Os DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) são fornecidos com MRTK fora da caixa e é o parâmetro predefinido para componentes interagiveis .
O recurso DefaultInteractableStates contém quatro estados e utiliza a implementação do InteractableStates
modelo de estado.
Predefinição: não está a acontecer nada, este é o estado base mais isolado.
Foco: o objeto está a ser apontado. Este é um único estado, nenhum outro estado está atualmente definido, mas irá eliminar a classificação Predefinida.
Prima: o objeto está a ser apontado e um botão ou mão está a premir. O estado Premir classifica Predefinição e Foco. Este estado também será definido como uma contingência para a Imprensa Física.
Desativado: o botão não deve ser interativo e os comentários visuais informarão o utilizador se, por algum motivo, este botão não for utilizável neste momento. Em teoria, o estado desativado pode conter todos os outros estados, mas quando Ativado é desativado, o Estado desativado supera todos os outros estados.
Um valor de bit (#) é atribuído ao estado consoante a ordem na lista.
Nota
Geralmente, é recomendado utilizar DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) ao criar componentes Interacionáveis .
No entanto, existem 17 estados interagiveis disponíveis que podem ser utilizados para impulsionar temas, embora alguns se destinam a ser conduzidos por outros componentes. Segue-se uma lista das pessoas com funcionalidades incorporadas.
- Visitado: o Interacionável foi clicado.
- Alternado: o botão está num estado desativado ou o índice de Dimensão é um número ímpar.
- Gesto: a mão ou o controlador foi premido e foi movido da posição original.
- VoiceCommand: foi utilizado um comando de voz para acionar o Interactable.
- PhysicalTouch: é atualmente detetada uma entrada tátil, utilizada
NearInteractionTouchable
para ativar. - Grab: A hand is currently grab in the bounds of the object, use
NearInteractionGrabbable
to enable
Ativado
Ativa ou não um Interacionável. Isto corresponde ao Interactable.IsEnabled
código em.
A propriedade ativada de um Interactable é diferente da propriedade ativada configurada através de GameObject/Component (ou seja, SetActive, etc.). Desativar o GameObject ou o MonoBehaviour Interagidor irá desativar a execução de tudo na classe, incluindo entradas, temas visuais, eventos, etc. Desativar através Interactable.IsEnabled
de irá desativar a maioria do processamento de entrada, repondo estados de entrada relacionados. No entanto, a classe continuará a executar todos os frames e a receber eventos de entrada que serão ignorados. Isto é útil para apresentar o Interactable num estado desativado que pode ser feito através de Temas Visuais. Um exemplo típico disto seria um botão submeter à espera que todos os campos de entrada necessários fossem concluídos.
Ações de Entrada
Selecione a ação de entrada no perfil de configuração de entrada ou mapeamento do controlador ao qual o componente Interactable deve reagir.
Esta propriedade pode ser configurada no runtime no código através de Interactable.InputAction
.
IsGlobal
Se for verdade, esta ação marcará o componente como um serviço de escuta de entrada global para a ação de entrada selecionada. O comportamento predefinido é falso, o que irá restringir a entrada apenas a este colisor interacionável /GameObject.
Esta propriedade pode ser configurada no runtime no código através de Interactable.IsGlobal
.
Comando de Voz
Comando de voz, a partir do Perfil de Comandos de Voz do MRTK, para acionar um evento OnClick para interação de voz.
Esta propriedade pode ser configurada no runtime no código através de Interactable.VoiceCommand
.
Requer Concentração
Se for verdadeiro, o comando de voz só ativará o Interacionável se e apenas se já tiver o foco de um ponteiro. Se for falso, o Interactable funcionará como um serviço de escuta global para o comando de voz selecionado. O comportamento predefinido é verdadeiro, uma vez que vários serviços de escuta de voz globais podem ser difíceis de organizar numa cena.
Esta propriedade pode ser configurada no runtime no código através de Interactable.VoiceRequiresFocus
.
Modo de Seleção
Esta propriedade define a lógica de seleção. Quando um Interacionável é clicado, itera para um nível de Dimensão seguinte.
As dimensões são semelhantes à classificação e definem um estado fora das entradas (ou seja, foco, premir, etc.). São úteis para definir estados de alternar ou outros estados de várias classificações associados a um botão. O nível de Dimensão atual é controlado por Interactable.DimensionIndex
.
Os modos de seleção disponíveis são:
- Botão - Dimensões = 1, simples clicável Interacionável
- Alternar - Dimensões = 2, Interacionável alterna entre o/ estadodesativado
- Várias dimensões - Dimensões>= 3, cada clique aumenta o nível de dimensão atual + 1. Útil para definir um estado de botão para uma lista, etc.
Interacionável também permite que vários Temas sejam definidos por Dimensão. Por exemplo, quando SelectionMode=Toggle, um tema pode ser aplicado quando o Interactable é desselecionado e outro tema aplicado quando o componente é selecionado.
O Modo de Seleção atual pode ser consultado no runtime através de Interactable.ButtonMode
. A atualização do modo no runtime pode ser obtida ao definir a Interactable.Dimensions
propriedade para corresponder à funcionalidade pretendida. Além disso, a dimensão atual, útil para os modos Desativar e Multidimensionar , pode ser acedida através de Interactable.CurrentDimension
.
Perfis interagiveis
Os perfis são itens que criam uma relação entre um GameObject e um Tema Visual. O perfil define que conteúdo será manipulado por um tema quando ocorrer uma alteração de estado.
Os temas funcionam muito como materiais. São objetos scriptable que contêm uma lista de propriedades que serão atribuídas a um objeto com base no estado atual. Os temas também são reutilizáveis e podem ser atribuídos em vários objetos UX interagiveis .
Repor Ao Destruir
Os temas visuais modificam várias propriedades num GameObject direcionado, dependente da classe e do tipo de motor de tema selecionados. Se Reset On Destroy for true quando o componente Interactable for destruído, o componente irá repor todas as propriedades modificadas de temas ativos para os respetivos valores originais. Caso contrário, quando destruído, o componente Interacionável deixará as propriedades modificadas tal como estão. Neste último caso, o último estado dos valores persistirá, a menos que seja alterado por outro componente externo. A predefinição é falsa.
Evento
Cada componente Interacionável tem um evento OnClick que é acionado quando o componente é simplesmente selecionado. No entanto, o Interactable pode ser utilizado para detetar eventos de entrada que não apenas o OnClick.
Clique no botão Adicionar Evento para adicionar um novo tipo de definição do Recetor de Eventos. Depois de adicionado, selecione o tipo de Evento pretendido.
)
Existem diferentes tipos de recetores de eventos para responder a diferentes tipos de entrada. O MRTK é fornecido com o seguinte conjunto de recetores fora da caixa.
InteractableAudioReceiver
InteractableOnClickReceiver
InteractableOnFocusReceiver
InteractableOnGrabReceiver
InteractableOnHoldReceiver
InteractableOnPressReceiver
InteractableOnToggleReceiver
InteractableOnTouchReceiver
Um recetor personalizado pode ser criado ao criar uma nova classe que expanda ReceiverBase
.
Exemplo de um Recetor de Eventos Desativado
Recetores interagiveis
O InteractableReceiver
componente permite que os eventos sejam definidos fora do componente Interacionável de origem. O InteractableReceiver irá escutar um tipo de evento filtrado acionado por outro Interacionável. Se a propriedade Interactable não for atribuída diretamente, a propriedade Âmbito de Pesquisa define a direção em que o InteractableReceiver escuta eventos que estão em si, num elemento principal ou num GameObject subordinado.
InteractableReceiverList
atua de forma semelhante, mas para uma lista de eventos correspondentes.
Criar eventos personalizados
Tal como os Temas Visuais, os eventos podem ser expandidos para detetar qualquer padrão de estado ou para expor a funcionalidade.
Os eventos personalizados podem ser criados de duas formas principais:
Expanda a
ReceiverBase
classe para criar um evento personalizado que será apresentado na lista pendente de tipos de eventos. Um evento do Unity é fornecido por predefinição, mas podem ser adicionados eventos adicionais do Unity ou o evento pode ser definido para ocultar eventos do Unity. Esta funcionalidade permite que um designer trabalhe com um engenheiro num projeto para criar um evento personalizado que o estruturador pode configurar no editor.Expanda a
ReceiverBaseMonoBehavior
classe para criar um componente de evento completamente personalizado que possa residir no objeto Interacionável ou noutro objeto. OReceiverBaseMonoBehavior
fará referência a Interacionável para detetar alterações de estado.
Exemplo de expansão ReceiverBase
A CustomInteractablesReceiver
classe apresenta informações de estado sobre um Interacionável e é um exemplo de como criar um Recetor de Eventos personalizado.
public CustomInteractablesReceiver(UnityEvent ev) : base(ev, "CustomEvent")
{
HideUnityEvents = true; // hides Unity events in the receiver - meant to be code only
}
Os seguintes métodos são úteis para substituir/implementar ao criar um Recetor de Eventos personalizado.
ReceiverBase.OnUpdate()
é um método abstrato que pode ser utilizado para detetar padrões/transições de estado. Além disso, os ReceiverBase.OnVoiceCommand()
métodos e ReceiverBase.OnClick()
são úteis para criar lógica de eventos personalizada quando a opção Interacionável está selecionada.
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
}
Apresentar campos de recetor de eventos personalizados no inspetor
Os scripts ReceiverBase utilizam InspectorField
atributos para expor propriedades personalizadas no inspetor. Eis um exemplo de Vector3, uma propriedade personalizada com informações de descrição e etiqueta. Esta propriedade será apresentada como configurável no inspetor quando um GameObject Interacionável estiver selecionado e tiver o tipo de Recetor de Eventos associado adicionado.
[InspectorField(Label = "<Property label>",Tooltip = "<Insert tooltip info>",Type = InspectorField.FieldTypes.Vector3)]
public Vector3 EffectOffset = Vector3.zero;
Como utilizar o Interactable
Criar um botão simples
Pode-se criar um botão simples ao adicionar o componente Interactable a um GameObject configurado para receber eventos de entrada. Pode ter um colisor nele ou numa criança para receber entrada. Se utilizar o GameObjects interacionável com uma IU do Unity baseada em GameObjects, deve estar no GameObject de Tela.
Dê um passo mais além no botão ao criar um novo perfil, atribuir o próprio GameObject e criar um novo tema. Além disso, utilize o evento OnClick para que algo aconteça.
Nota
Tornar um botão premido requer o PressableButton
componente. Além disso, o PhysicalPressEventRouter
componente é necessário para funilizar eventos de imprensa para o componente Interacionável .
Criar botões de alternar e de várias dimensões
Botão de alternar
Para ativar/desativar um botão, altere o Selection Mode
campo para escrever Toggle
. Na secção Perfis , é adicionado um novo tema alternado para cada perfil que é utilizado quando o Interacionável é ativado.
Enquanto o SelectionMode
está definido como Ativar/Desativar, a caixa de verificação IsToggled pode ser utilizada para definir o valor predefinido do controlo na inicialização do runtime.
CanSelect significa que o Interactable pode ir de desligado para ligado enquanto CanDeselect significa o inverso.
Os programadores podem utilizar as SetToggled
interfaces e IsToggled
para obter/definir o estado de alternar de um Interacionável através de 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;
Ativar/desativar coleção de botões
É comum ter uma lista de botões de alternar onde apenas um pode estar ativo a qualquer momento, também conhecido como um conjunto radial ou botões de opção, etc.
Utilize o InteractableToggleCollection
componente para ativar esta funcionalidade. Este controlo garante que apenas um Interacionável é ativado a qualquer momento. O RadialSet (Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/RadialSet.prefab) também é um excelente ponto de partida.
Para criar um grupo de botões radial personalizado:
- Criar vários GameObjects/botões Interagiveis
- Defina cada Interacionável com SelectionMode = Toggle, CanSelect = true e CanDeselect = false
- Crie um GameObject principal vazio em todos os Interactables e adicione o componente InteractableToggleCollection
- Adicionar todos os Interativadores à Lista de Alternar na InteractableToggleCollection
- Defina a propriedade InteractableToggleCollection.CurrentIndex para determinar qual o botão selecionado por predefinição no início
Botão multidimensional
O modo de seleção de Várias Dimensões é utilizado para criar botões sequenciais ou um botão com mais de dois passos, como controlar a velocidade com três valores, Fast (1x), Faster (2x) ou Fastest (3x).
Sendo as dimensões um valor numérico, podem ser adicionados até 9 temas para controlar a etiqueta de texto ou a textura do botão para cada definição de velocidade, utilizando um tema diferente para cada passo.
Cada evento de clique avançará DimensionIndex
1 no runtime até que o Dimensions
valor seja atingido. Em seguida, o ciclo será reposto para 0.
Os programadores podem avaliar o DimensionIndex
para determinar que dimensão está atualmente ativa.
// 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();
Criar Interacionável no runtime
Pode ser facilmente adicionado a qualquer GameObject durante o runtime. O exemplo seguinte demonstra como atribuir um perfil com um 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 interagiveis através de código
Pode-se adicionar uma ação ao evento base Interactable.OnClick
através de código com o seguinte exemplo.
public static void AddOnClick(Interactable interactable)
{
interactable.OnClick.AddListener(() => Debug.Log("Interactable clicked"));
}
Utilize a Interactable.AddReceiver<T>()
função para adicionar recetores de eventos dinamicamente no runtime.
O código de exemplo abaixo demonstra como adicionar um InteractableOnFocusReceiver, que escuta a entrada/saída do foco e, além disso, define o código de ação a executar quando as instâncias de eventos são acionados.
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"));
}
O código de exemplo abaixo demonstra como adicionar um InteractableOnToggleReceiver, que escuta transições de estado selecionadas/desselecionadas em Interativadores com capacidade de alternar e, além disso, define o código de ação a executar quando as instâncias de eventos são acionadas.
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"));
}