Використання карт дій для призначення кнопок поведінці гри

Сторінка оновлюється :
Дата створення сторінки :

Середовище перевірки

Вікна
  • вікна 11
Редактор єдності
  • 2020.3.25f1
Пакет системи введення
  • 1.2.0

Передумови для цієї поради

Наступні настройки були зроблені заздалегідь як передумова для опису цієї поради.

Про карти дій

Програми введення користувача на клавіатурах, мишах і геймпадах в основному заявляли про те, що при натисканні кнопки виконується певна дія. У карті дій, наприклад, можна визначити дію «стрибка» і призначити йому кнопки контролера і клавіші клавіатури. В результаті програмі потрібно лише описати процес при виконанні певної дії. Навіть якщо ви призначите кнопку на іншому контролері як заднім числом, ви можете застосувати її, не змінюючи операційну програму.

Створення карти дій

Тут я хотів би створити карту дій і відобразити введену користувачем інформацію в тексті. Існує кілька способів отримання даних користувачем за допомогою карт дій.

Клацніть правою кнопкою миші будь-яку папку у проекті, щоб створити дію введення. Розташування папки, яку потрібно створити, довільне, але, будь ласка, керуйте нею відповідно до вашого проекту. Ім'я файлу також довільне, але тут InputActionSample воно .

При подвійному клацанні створеного файлу відобразиться наступне вікно.

Спочатку натисніть кнопку + у Картах дій, щоб створити карту дій. Як одиниця створення, якщо зміст операції змінюється залежно від сцени, він буде визначений у цьому блоці. Наприклад, у випадку екшену з бічною прокруткою вміст операції змінюється під час дії та в меню, тому ви створите карту дій для кожного.

Тут, як приклад, ми визначаємо дію бічної прокрутки і називаємо її "SideScrollActionMap".

Далі створіть Дії. Оскільки це зразок, я не буду робити багато з них, але тут ми створимо дії «Move» для руху і «Attack» для атаки. Оскільки один вже створений, будь ласка, змініть ім'я або створіть нове, натисніть кнопку + у верхньому правому куті та введіть його.

Спочатку налаштуйте конфігурацію переміщення. Контролер передбачає, що ви використовуєте клавіші флешки, D-pad та курсору клавіатури. У разі дії бічної прокрутки бувають випадки, коли використовуються тільки вліво і вправо, але тут ми припускаємо, що ви використовуєте чотири напрямки, розглядаючи стрибок верхньою клавішею і присідання клавішею вниз.

Коли ви вибираєте Перемістити, праворуч є вибір Тип дії, тому встановіть для цього значення «Значення».

Нижче ви побачите тип елемента керування, тому виберіть Vector2. Це пояснюється тим, що верх і низ призначаються Y, а лівий і правий - X.

Потім виберіть ключ, який потрібно призначити цій події. Виберіть "Без прив'язування" посередині та виберіть "Контур" праворуч. Тут вибираємо GamePad LeftStick.

Це прив'язує LeftStick GamePad до ходу.

Щоб прив'язати й інші контролери, виберіть «Додати прив'язку» на кнопці + праворуч від кнопки «Перемістити».

Тепер, коли додано No Binding, ми призначаємо Dpad для GamePad.

Таким чином, ви можете додати тип контролера, який ви хочете підтримувати, а також клавіші та флешки. Також є можливість встановити його спеціально під конкретну ігрову консоль.

Палички та Dpads - це кнопки, які приймають вгору, вниз, вліво та вправо, тому їх можна додати за допомогою цього, але у випадку клавіатур усі вони є одиночними клавішами, тому немає визначення для вгору, вниз, ліворуч та праворуч. Щоб налаштувати клавіатуру вгору, вниз, вліво або вправо, виберіть «Додати вгору вниз вліво вправо» на кнопці +.

Потім буде додано 2D-вектор, і ви можете призначити його кожному вгору вниз ліворуч праворуч, як показано на малюнку нижче.

Наприклад, якщо ви використовуєте Вгору, встановіть "Стрілка вгору" на клавіатурі. До речі, якщо вам важко знайти ключ, ви можете легко вибрати його, натиснувши цільову клавішу при натисканні кнопки "Прослухати".

Тепер для параметра Вгору встановлено значення Стрілка вгору.

Так само встановіть Вниз, Ліворуч і Праворуч, і все готово.

Звичайно, можна встановити не тільки клавіші курсору, але і WASD.

Далі налаштовуємо Атаку. Атаку легко призначити, оскільки це одна кнопка. Спочатку виберіть Атакувати і переконайтеся, що Тип дії - це кнопка.

Потім виберіть "Без прив'язки" і виберіть кнопку, яку потрібно призначити зі Шляху.

Якщо ви хочете додати більше, виберіть «Додати прив'язку» на кнопці +.

Додайте стільки, скільки вам потрібно. Оскільки вона розглядається як кнопка, клавіатуру можна налаштувати так само, як і ігровий контролер.

Коли всі налаштування будуть завершені, натисніть «Зберегти актив», щоб зберегти. Можна закрити це вікно.

Нарешті, з файлом вхідних дій проекту (в даному випадку файлом InputActionSample, який ви створили раніше), поставте галочку навпроти пункту "Create C# Class" в інспекторі. Параметр буде доданий, але натисніть кнопку "Застосувати" як є.

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

Як отримувати вхідну інформацію

Існує кілька способів отримання вхідних даних на основі карти дій. Ця порада пояснює три моделі, але краще зосередитися на одному з них, коли насправді створюєте гру. Якщо використовувати їх окремо, управляти буде клопітно.

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

Отримання інформації для вводу в папці "Надсилання повідомлень"

Перший спосіб тут - як отримувати вхідну інформацію в "Відправці повідомлень".

Цього разу я хочу відобразити введену інформацію в тексті, тому розміщу текстовий об'єкт.

Також, оскільки ця порада буде намагатися отримати багаторазову вхідну інформацію, ми створимо порожній об'єкт для встановлення компонента окремо. Ім'я може бути будь-яким.

Далі додайте компонент Player Input до порожнього об'єкта. Вхід програвача є важливим компонентом для підключення карт дій і скриптів.

У «Додати компонент» в категорії «Вхідні дані» є «Введення програвача», тому додайте його.

Після додавання компонента Player Input встановіть карту дій, яку ви створили в розділі "Дії". Скиньте його з проекту або виберіть на значку + праворуч.

Переконайтеся, що карта за промовчанням – це карта, створена на карті дій.

Переконайтеся, що поведінка "Надсилати повідомлення".

Далі створюємо скрипт. Ім'я файлу може бути будь-яким, але ось InputSendMessage воно .

Сценарій виглядає так:

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class InputSendMessage : MonoBehaviour
{
  /// <summary>情報を表示させるテキストオブジェクト。</summary>
  [SerializeField] private Text TextObject;

  /// <summary>
  /// Move アクションが実行されたときに呼ばれる。
  /// </summary>
  /// <param name="inputValue">入力量。</param>
  public void OnMove(InputValue inputValue)
  {
    var vec = inputValue.Get<Vector2>();
    TextObject.text = $"Move:({vec.x:f2}, {vec.y:f2})\n{TextObject.text}";
  }

  /// <summary>
  /// Attack アクションが実行されたときに呼ばれる。
  /// </summary>
  public void OnAttack(InputValue inputValue)
  {
    TextObject.text = $"Attack:{inputValue.isPressed}\n{TextObject.text}";
  }
}
  • До об'єкта прикріплено вхід програвача, який встановлює «Надсилання повідомлень»
  • Успадкування від моноповедінки

Якщо умови дотримані, то якщо визначити метод під назвою «OnXXXXXXXXX», Цільовий метод буде називатися при виконанні заданої операції дії. "XXXXXXXX" – це назва Дій, створених на карті дій. Тут ми створили дії "Move" і "Attack", тому назви методів - "OnMove" і "OnAttack" відповідно.

OnMove Введену суму можна отримати з аргументу InputValue . Оскільки для параметра Control Type встановлено значення "Vector 2", вхідне значення InputValue.Get<Vector2> буде отримано в .

OnAttackInputValue.isPressed Ви також можете зрозуміти, чи натискаєте ви.

Після збереження сценарію вкладіть його до об'єкта, який містить компонент вводу програвача. Також налаштуйте текстовий об'єкт для відображення.

Запустіть гру і подивіться. Цього разу я включив визначення геймпада та клавіатури, тому він повинен працювати незалежно від того, яким з них ви керуєте.

Як видно, при його переміщенні видно, що метод викликається тільки тоді, коли відбувається зміна значення з попереднього стану. Наприклад, при русі палиці вліво вона називається однодумно, але не вліво (- OnMove 1,0). OnMove Кнопка «Атака» також реагує тільки в момент її натискання, а якщо її натиснути і утримувати, то метод не викликається.

Тому я думаю, що ідеальним використанням є не виконувати обробку гри, коли викликається OnXXXXXXXXX, а зберігати лише вхідний вміст і використовувати ці значення в обробці оновлень гри.

До речі, в поточному стані вона не викликається при відпуску кнопки, тому визначити, коли OnAttack кнопка відпущена, не представляється можливим. Щоб відповісти на це, виберіть дію Атака, яка визначає кнопку в налаштуваннях карти дій і додайте «Натиснути» з «Взаємодії». Після цього встановіть поведінку тригера доданого натискання на "Натисніть і відпустіть" і збережіть його.

При виконанні можна побачити, що викликається навіть OnAttack тоді, коли кнопка відпущена. isPressed false Оскільки він стає , також можна визначити, чи є це термінами випуску.

До речі, будь ласка, видаліть цю взаємодію, оскільки вона не буде використовуватися в майбутньому.

Отримуйте вхідні дані за допомогою Виклик подій єдності

Другий спосіб отримання вхідних даних - Виклик подій єдності, тому давайте спробуємо це. Як згадувалося вище, використання декількох методів введення може спричинити конфліктну обробку, тому, якщо ввімкнено іншу обробку, вимкніть її.

Спочатку розташуйте текстовий об'єкт так, щоб можна було виводити вхідну інформацію.

Виклик подій єдності створює порожній об'єкт, який виконує пов'язані операції.

Додайте Input > Player Input до порожнього об'єкта.

Установіть файл карти дій, створений для папки Дії (у цьому випадку InputActionSample), а для створеної вами карти дій (у цьому випадку SideScrollActionMap) установіть значення Карта за промовчанням. Встановіть поведінку для виклику подій єдності.

Створіть сценарій. Назва довільна, але в даному випадку InputInvokeUnityEvents це .

Сценарій виглядає так:

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class InputInvokeUnityEvents : MonoBehaviour
{
  /// <summary>情報を表示させるテキストオブジェクト。</summary>
  [SerializeField] private Text TextObject;

  /// <summary>
  /// Move 操作を行ったときに呼ばれる。
  /// </summary>
  /// <param name="context">コールバック内容。</param>
  public void OnMove(InputAction.CallbackContext context)
  {
    var vec = context.ReadValue<Vector2>();
    TextObject.text = $"Move:({vec.x:f2}, {vec.y:f2})\n{TextObject.text}";
  }

  /// <summary>
  /// Move 操作を行ったときに呼ばれる。
  /// </summary>
  /// <param name="context">コールバック内容。</param>
  public void OnAttack(InputAction.CallbackContext context)
  {
    var value = context.ReadValueAsButton();
    TextObject.text = $"Attack:{value}\n{TextObject.text}";
  }
}

Ім'я OnMoveOnAttack методу, яке викликається, коли користувач взаємодіє з ним, - , як у випадку з Send Messages. У Invoke Unity Events ви можете встановити ім'я цього методу, як вам подобається.

Коли кожен викликається, він передається як InputAction.CallbackContext аргумент, тому ви можете отримати статус введення звідти. Якщо в дії встановити «значення», то можна отримати його в методі, а якщо ReadValue встановити ReadValueAsButton «кнопку» - то отримати в способі.

Після збереження сценарію прикріпіть вхід програвача до встановленого вами об'єкта і встановіть відображення текстового об'єкта.

Далі розгорніть "Подія" та "Назва карти дій (SideScrollActionMap)" у введенні гравця, і ви повинні побачити дії "Переміщення" та "Атака", які ви створили.

Спочатку натисніть кнопку + на Перемістити, щоб додати його.

Об'єкт у нижньому лівому куті є вашим власним об'єктом, а функція встановлена на метод, який ви щойно створили OnMove .

Також налаштуйте подію атаки.

Запустіть гру, щоб побачити, як вона працює.

В основному він викликається тільки при зміні того ж значення, що і Send Messages, але з якоїсь причини метод може викликатися двічі одночасно. Я не знаю причини, але думаю, що це, ймовірно, тому, що процес запуску та безперервний процес працюють одночасно. Однак, думаю, що немає ніякої проблеми, якщо зберегти тільки введене значення, як у випадку з Send Messages і виконувати фактичну обробку гри окремо в процесі оновлення.

Використання автоматично створеного сценарію для отримання вхідної інформації

У третьому розділі описано, як отримати вхідну інформацію за допомогою сценарію, створеного з файлу карти дій.

Оскільки існує ймовірність конфліктів з іншими процесами придбання, вимкніть інші процеси придбання.

Помістіть текстовий об'єкт для відображення вхідної інформації.

Також створіть порожній об'єкт для отримання вхідної інформації. У цій статті використовується автоматично згенерований сценарій, тому додавати введення даних програвачем не потрібно.

Сценарій, автоматично згенерований з карти дій, є просто бібліотекою, тому створіть окремий сценарій управління. Назва довільна, але в даному випадку InputScript це .

Сценарій виглядає так:

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class InputScript : MonoBehaviour
{
  /// <summary>情報を表示させるテキストオブジェクト。</summary>
  [SerializeField] private Text TextObject;

  /// <summary>アクションマップから自動生成されたクラス。</summary>
  private InputActionSample _actionMap;

  private void Awake()
  {
    // 各操作を行ったときに呼ばれるイベントを設定する
    _actionMap = new InputActionSample();
    _actionMap.SideScrollActionMap.Move.performed += context => OnMove(context);
    _actionMap.SideScrollActionMap.Attack.performed += context => OnAttack(context);
  }

  private void OnEnable()
  {
    // このオブジェクトが有効になったときにアクションマップを有効にする
    _actionMap.Enable();
  }

  private void OnDisable()
  {
    // このオブジェクトが無効になったときにアクションマップが余計な動作を起こさないように無効にする
    _actionMap.Disable();
  }

  /// <summary>
  /// Move 操作をした時に呼ばれるメソッドです。
  /// </summary>
  /// <param name="context">コールバックパラメータ。</param>
  public void OnMove(InputAction.CallbackContext context)
  {
    // Move の入力量を取得
    var vec = context.ReadValue<Vector2>();
    TextObject.text = $"Move:({vec.x:f2}, {vec.y:f2})\n{TextObject.text}";
  }

  /// <summary>
  /// Attack 操作をした時に呼ばれるメソッドです。
  /// </summary>
  /// <param name="context">コールバックパラメータ。</param>
  public void OnAttack(InputAction.CallbackContext context)
  {
    // Attack ボタンの状態を取得
    var value = context.ReadValueAsButton();
    TextObject.text = $"Attack:{value}\n{TextObject.text}";
  }
}

Визначте автоматично згенерований клас InputActionSample з карти дій у полі. Цей клас визначає кожен набір дій на карті дій, і ви можете встановити події, які викликаються під час виконання цих дій.

Awake У методі InputActionSample створюється екземпляр і задається подія, викликана в момент дії. Коли OnMoveви виконуєте ці операції, тепер називається метод , OnAttack .

Однак, оскільки ми тільки задаємо тут подію, нам OnEnable потрібно викликати метод, коли Enable викликається включити карту дій.

Крім того, оскільки поведінка введення користувача розглядається як глобальна операція, Щоб карта дій не OnDisable робила зайвих після того, як цей об'єкт буде визнаний недійсним, викликаємо метод в Disable методі, щоб відключити його.

Після збереження сценарію прикріпіть його до створеного вами порожньому об'єкту і задайте текстовий об'єкт для відображення.

Запустіть гру, щоб побачити, як вона працює.

Як бачимо, метод не викликається, коли OnMove операція Move стає (0, 0). Я не знаю чому, але здається, що виконана подія насправді займає лише ту, у якій увімкнено натискання клавіш.

До речі, якщо ви не встановили Взаємодії в карті дій для Атаки, вона не буде викликатися при OnAttack відпусканні кнопки.

Щоб впоратися з canceled цим, потрібно налаштувати подію. Якщо ви не хочете виконувати спеціальну обробку при (0, 0), можна викликати метод як він є OnMove . Те ж саме стосується і Attack.

private void Awake()
{
  // 各操作を行ったときに呼ばれるイベントを設定する
  _actionMap = new InputActionSample();
  _actionMap.SideScrollActionMap.Move.performed += context => OnMove(context);
  _actionMap.SideScrollActionMap.Attack.performed += context => OnAttack(context);
  _actionMap.SideScrollActionMap.Move.canceled += context => OnMove(context);       // 追加
  _actionMap.SideScrollActionMap.Attack.canceled += context => OnAttack(context);   // 追加
}

Запустіть і переконайтеся, що з'являється кнопка Move:(0, 0) або Attack:False.