Взаимодействуемые — MRTK2

Интерактивный объект

Компонент Interactable — это контейнер "все в одном", который позволяет легко взаимодействовать с любым объектом и реагировать на входные данные. Интерактивный компонент действует как универсальный для всех типов ввода, включая касание, лучи рук, речь и т. д., и направляет эти взаимодействия в события и визуальные ответы темы . Этот компонент предоставляет простой способ создания кнопок, изменения цвета объектов с фокусом и многого другого.

Настройка интерактивных компонентов

Компонент позволяет использовать три основных раздела конфигурации:

  1. Общая конфигурация входных данных
  2. Визуальные темы , предназначенные для нескольких объектов GameObject
  3. Обработчики событий

Общие параметры ввода

Общие параметры взаимодействия

Состояния

States — это параметр ScriptableObject , определяющий этапы взаимодействия, например нажатие или наблюдение, для интерактивных профилей и визуальных тем.

DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) поставляется с MRTK по умолчанию и является параметром по умолчанию для компонентов Interactable.

Пример объекта ScriptableObject состояния в инспекторе

Ресурс DefaultInteractableStates содержит четыре состояния и использует реализацию InteractableStates модели состояния.

  • По умолчанию: ничего не происходит, это наиболее изолированное базовое состояние.

  • Фокус: объект указывает на. Это одно состояние, другие состояния в настоящее время не заданы, но оно будет ранжироваться по умолчанию.

  • Нажатие: объект указывает на и нажимается кнопка или рука. Состояние прессы оценивается по умолчанию и фокусу. Это состояние также будет установлено в качестве резервного значения Физическое нажатие.

  • Отключено: кнопка не должна быть интерактивной, и визуальная обратная связь позволит пользователю узнать, если по какой-либо причине эта кнопка не используется в настоящее время. Теоретически отключенное состояние может содержать все остальные состояния, но если параметр Enabled отключен, состояние Disabled имеет значение для всех остальных состояний.

Битовое значение (#) присваивается состоянию в зависимости от порядка в списке.

Примечание

Обычно рекомендуется использовать DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States/DefaultInteractableStates.asset) при создании взаимодействуемых компонентов.

Однако существует 17 взаимодействуемых состояний, которые можно использовать для управления темами, хотя некоторые из них предназначены для управления другими компонентами. Ниже приведен список со встроенными функциями.

  • Посещено: выбран элемент Interactable (Интерактивный).
  • Переключение: кнопка находится в состоянии переключения или индекс измерения является нечетным числом.
  • Жест. Нажата рука или контроллер, которые были перемещены из исходного положения.
  • VoiceCommand: голосовая команда использовалась для активации interactable.
  • PhysicalTouch: в настоящее время обнаружен сенсорный ввод, используйте для NearInteractionTouchable включения.
  • Захват: рука в настоящее время захватывает в границах объекта, используйте NearInteractionGrabbable для включения

Enabled

Указывает, будет ли включен интерактивный компонент. Это соответствует в коде Interactable.IsEnabled .

Свойство enabled объекта Interactable отличается от свойства enabled, настроенного с помощью GameObject/Component (например, SetActive и т. д.). Отключение GameObject или Interactable MonoBehaviour приведет к отключению выполнения всех элементов класса, включая входные данные, визуальные темы, события и т. д. Отключение с помощью Interactable.IsEnabled приведет к отключению большинства операций ввода, сбросив связанные входные состояния. Однако класс по-прежнему будет запускать каждый кадр и получать входные события, которые будут игнорироваться. Это полезно для отображения взаимодействуемого объекта в отключенном состоянии, что можно сделать с помощью визуальных тем. Типичным примером этого является кнопка отправки, ожидая заполнения всех необходимых полей ввода.

Действия ввода

Выберите действие ввода из конфигурации ввода или профиля сопоставления контроллера, на который должен реагировать взаимодействующий компонент.

Это свойство можно настроить во время выполнения в коде с помощью Interactable.InputAction.

IsGlobal

Если значение равно true, компонент будет помечаться как глобальный прослушиватель входных данных для выбранного действия ввода. По умолчанию используется значение false, которое ограничивает входные данные только этим взаимодействуемым коллайдером или GameObject.

Это свойство можно настроить во время выполнения в коде с помощью Interactable.IsGlobal.

Команда "Речь"

Голосовая команда из профиля речевых команд MRTK для активации события OnClick для голосового взаимодействия.

Это свойство можно настроить во время выполнения в коде с помощью Interactable.VoiceCommand.

Требуется фокус

Если значение равно true, голосовая команда активирует объект Interactable только в том случае, если фокус уже установлен с указателя. Если значение равно false, интерактивный объект будет выступать в качестве глобального прослушивателя для выбранной голосовой команды. Поведение по умолчанию — true, так как несколько глобальных прослушивателей речи может быть трудно организовать в сцене.

Это свойство можно настроить во время выполнения в коде с помощью Interactable.VoiceRequiresFocus.

Режим выделения

Это свойство определяет логику выбора. При нажатии кнопки Interactable выполняется переход к следующему уровню измерения . Измерения похожи на ранг и определяют состояние за пределами входных данных (например, фокус, нажатие и т. д.). Они полезны для определения состояний переключения или других состояний с несколькими рангами, связанных с кнопкой. Текущий уровень измерения отслеживается с помощью Interactable.DimensionIndex.

Доступные режимы выбора:

  • Кнопку - Измерения = 1, простой интерактивный интерактивный
  • Переключение - Измерения = 2, интерактивные варианты между/выключенным состоянием
  • Многомерный - Размеры>= 3, каждый щелчок увеличивает текущий уровень измерения + 1. Полезно для определения состояния кнопки для списка и т. д.

Взаимодействие также позволяет определить несколько тем для каждого измерения. Например, если SelectionMode=Toggle, одна тема может применяться при отмене выборавзаимодействуемого элемента, а другая — при выборе компонента.

Текущий режим выбора можно запросить во время выполнения через Interactable.ButtonMode. Обновить режим во время выполнения можно, задав Interactable.Dimensions свойство в соответствии с требуемой функциональностью. Кроме того, доступ к текущему измерению, удобному для режимов переключения и многомерности , можно получить через Interactable.CurrentDimension.

Взаимодействуемые профили

Профили — это элементы, которые создают связь между GameObject и визуальной темой. Профиль определяет, каким содержимым будет управлять тема при изменении состояния.

Темы во многом похожи на материалы. Это объекты, доступные для сценариев, которые содержат список свойств, которые будут назначены объекту на основе текущего состояния. Темы также можно повторно использовать и могут назначаться нескольким взаимодействуемым объектам пользовательского интерфейса.

Сброс при уничтожении

Визуальные темы изменяют различные свойства целевого объекта GameObject в зависимости от класса и типа выбранного обработчика тем. Если параметр Reset On Destroy имеет значение true при уничтожении взаимодействуемого компонента, компонент сбросит все измененные свойства из активных тем до исходных значений. В противном случае при уничтожении компонент Interactable оставит все измененные свойства как есть. В последнем случае последнее состояние значений сохранится, если оно не будет изменено другим внешним компонентом. Значение по умолчанию — false.

Профилирование

События

Каждый компонент, поддерживающий взаимодействие , имеет событие OnClick , которое срабатывает при простом выборе компонента. Однако Interactable можно использовать для обнаружения событий ввода, отличных от OnClick.

Нажмите кнопку Добавить событие , чтобы добавить новый тип определения приемника событий. После добавления выберите нужный тип события.

Пример событий)

Существуют различные типы приемников событий для реагирования на различные типы входных данных. MRTK поставляется со следующим набором приемников в комплекте.

Пользовательский приемник можно создать, создав новый класс, расширяющий ReceiverBase.

Пример приемника переключения событий

Пример приемника событий переключения

Взаимодействуемые получатели

Компонент InteractableReceiver позволяет определять события за пределами исходного взаимодействующего компонента. InteractableReceiver будет прослушивать отфильтрованный тип события, активируемый другим Interactable. Если свойство Interactable не назначено напрямую, то свойство Область поиска определяет направление, в котором InteractableReceiver прослушивает события, которые либо сами по себе, в родительском объекте, либо в дочернем GameObject.

InteractableReceiverList действует аналогичным образом, но для списка соответствующих событий.

Интерактивный резивер

Создание пользовательских событий

Как и визуальные темы, события можно расширить для обнаружения любого шаблона состояния или предоставления функциональных возможностей.

Пользовательские события можно создать двумя main способами:

  1. Расширьте класс , ReceiverBase чтобы создать пользовательское событие, которое будет отображаться в раскрывающемся списке типов событий. Событие Unity предоставляется по умолчанию, но можно добавить дополнительные события Unity или настроить для этого события скрытие событий Unity. Эта функция позволяет конструктору работать с инженером над проектом, чтобы создать пользовательское событие, которое конструктор может настроить в редакторе.

  2. Расширьте класс , ReceiverBaseMonoBehavior чтобы создать полностью пользовательский компонент события, который может находиться в объекте Interactable или другом объекте. Объект ReceiverBaseMonoBehavior будет ссылаться на интерактивный объект для обнаружения изменений состояния.

Пример расширения ReceiverBase

Класс CustomInteractablesReceiver отображает сведения о состоянии объекта Interactable и является примером создания пользовательского приемника событий.

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

Следующие методы полезны для переопределения и реализации при создании пользовательского приемника событий. ReceiverBase.OnUpdate() — это абстрактный метод, который можно использовать для обнаружения шаблонов и переходов состояния. Кроме того, ReceiverBase.OnVoiceCommand() методы и ReceiverBase.OnClick() полезны для создания пользовательской логики событий при выборе параметра Взаимодействуемый .

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
}
Отображение полей настраиваемого приемника событий в инспекторе

Скрипты ReceiverBase используют InspectorField атрибуты для предоставления настраиваемых свойств в инспекторе. Ниже приведен пример Vector3, пользовательского свойства с подсказкой и сведениями о метки. Это свойство будет отображаться как настраиваемое в инспекторе, если выбран интерактивный GameObject и добавлен связанный тип приемника событий .

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

Использование интерактивных компонентов

Создание простой кнопки

Можно создать простую кнопку, добавив компонент Interactable в GameObject, настроенный для получения событий ввода. Он может иметь коллайдер на нем или на дочернем объекте для получения входных данных. При использовании Interactable с GameObjects на основе пользовательского интерфейса Unity он должен находиться в разделе Canvas GameObject.

Запустите кнопку еще на один шаг, создав новый профиль, назначив сам GameObject и создав новую тему. Кроме того, используйте событие OnClick , чтобы что-то произошло.

Примечание

Для нажатия кнопки требуется PressableButton компонент . Кроме того, PhysicalPressEventRouter компонент необходим для воронки событий прессы в компонент Interactable .

Создание переключателей и многомерных кнопок

Выключатель

Чтобы сделать кнопку с возможностью переключения, измените Selection Mode поле на тип Toggle. В разделе Профили для каждого профиля, используемого при включении интерактивного интерфейса, добавляется новая переключение темы.

SelectionMode Хотя параметр имеет значение Toggle, поле IsToggled проверка можно использовать для задания значения по умолчанию элемента управления при инициализации среды выполнения.

CanSelect означает , что интерактивный объект может переходить от выключения к включену , а CanDeselect — обратный.

Пример переключения визуальных тем профиля

Разработчики могут использовать SetToggled интерфейсы и IsToggled для получения или задания состояния переключателя объекта Interactable с помощью кода.

// 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;
Коллекция переключателей

Как правило, имеется список переключателей, где в любой момент времени может быть активен только один из них, также известный как радиальный набор или переключатели и т. д.

Используйте компонент , InteractableToggleCollection чтобы включить эту функцию. Этот элемент управления гарантирует, что в любой момент времени включен только один интерактивный компонент. RadialSet (Assets/MRTK/SDK/Features/UX/Interactable/Prefabs/RadialSet.prefab) также является отличной отправной точкой.

Чтобы создать пользовательскую группу радиальных кнопок, выполните приведенные далее действия.

  1. Создание нескольких интерактивных объектов и кнопок gameObjects
  2. Задайте для каждого объекта Interactable with SelectionMode = Toggle, CanSelect = true, and CanDeselect = false
  3. Создайте пустой родительский объект GameObject для всех объектов Interactable и добавьте компонент InteractableToggleCollection .
  4. Добавление всех интерактивных элементов в ToggleList в Коллекции InteractableToggleCollection
  5. Задайте свойство InteractableToggleCollection.CurrentIndex , чтобы определить, какая кнопка выбрана по умолчанию при запуске
Переключение коллекции

Многомерная кнопка

Режим выбора с несколькими измерениями используется для создания последовательных кнопок или кнопки с более чем двумя шагами, например управление скоростью с тремя значениями: Быстрый (1x), Быстрый (2x) или Самый быстрый (3x).

Если измерения имеют числовое значение, можно добавить до 9 тем для управления текстовой меткой или текстурой кнопки для каждого параметра скорости, используя другую тему для каждого шага.

Каждое событие щелчка DimensionIndex перемещает на 1 во время выполнения, пока не Dimensions будет достигнуто значение. Затем цикл сбрасывается до 0.

Пример многомерного профиля

Разработчики могут оценить , DimensionIndex чтобы определить, какое измерение активно в данный момент.

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

Создание взаимодействуемого во время выполнения

Интерактивный объект можно легко добавить в любой GameObject во время выполнения. В следующем примере показано, как назначить профиль с визуальной темой.

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

Интерактивные события с помощью кода

Можно добавить действие в базовое Interactable.OnClick событие с помощью кода, приведенного в следующем примере.

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

Используйте функцию для динамического Interactable.AddReceiver<T>() добавления приемников событий во время выполнения.

В приведенном ниже примере кода показано, как добавить InteractableOnFocusReceiver, который прослушивает ввод и выход фокуса, а также определяет код действия, который будет выполняться при срабатывании экземпляров события.

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

В приведенном ниже примере кода показано, как добавить InteractableOnToggleReceiver, который прослушивает выбранные и отмененные переходы состояния в интерактивных объектах с возможностью переключения и, кроме того, определяет код действия, выполняемого при срабатывании экземпляров события.

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

См. также раздел