Interacionável — MRTK2

Interacionável

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:

  1. Configuração de entrada geral
  2. Temas Visuais direcionados para vários GameObjects
  3. Processadores de eventos

Definições de entrada gerais

Definições Gerais Interacionáveis

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 .

Estado ScriptableObject exemplo no inspetor

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.

Nomes de perfil

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.

Exemplo de eventos)

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.

Um recetor personalizado pode ser criado ao criar uma nova classe que expanda ReceiverBase.

Exemplo de Ativar/Desativar Recetor de Eventos

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.

Reciver interagiável

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:

  1. 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.

  2. Expanda a ReceiverBaseMonoBehavior classe para criar um componente de evento completamente personalizado que possa residir no objeto Interacionável ou noutro objeto. O ReceiverBaseMonoBehavior 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.

Exemplo de Ativar/Desativar Temas Visuais do Perfil

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:

  1. Criar vários GameObjects/botões Interagiveis
  2. Defina cada Interacionável com SelectionMode = Toggle, CanSelect = true e CanDeselect = false
  3. Crie um GameObject principal vazio em todos os Interactables e adicione o componente InteractableToggleCollection
  4. Adicionar todos os Interativadores à Lista de Alternar na InteractableToggleCollection
  5. Defina a propriedade InteractableToggleCollection.CurrentIndex para determinar qual o botão selecionado por predefinição no início
Ativar/desativar coleção

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.

Exemplo de perfil multidimensional

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

Ver também