Używanie map akcji do przypisywania przycisków do zachowań w grze

Strona zaktualizowana :
Data utworzenia strony :

Środowisko weryfikacji

Windows
  • Okna 11
Edytor Unity
  • 2020.3.25f1
Pakiet systemu wejściowego
  • 1.2.0

Wymagania wstępne dotyczące tej porady

Poniższe ustawienia zostały wcześniej wprowadzone jako przesłanka do opisu tej wskazówki.

Informacje o mapach akcji

Programy wprowadzające dane użytkownika na klawiaturach, myszach i gamepadach zasadniczo stwierdzały, że pewna akcja została wykonana po naciśnięciu przycisku. Na przykład na mapie akcji można zdefiniować akcję "skakania" i przypisać do niej przyciski kontrolera i klawiatury. W rezultacie program musi opisać proces tylko wtedy, gdy wykonywana jest określona akcja. Nawet jeśli przypiszesz przycisk do innego kontrolera po namyśle, możesz go zastosować bez zmiany programu operacyjnego.

Tworzenie mapy działania

Tutaj chciałbym stworzyć mapę akcji i wyświetlić informacje wejściowe użytkownika w tekście. Istnieje kilka sposobów na uzyskanie danych wejściowych użytkownika za pomocą map akcji.

Kliknij prawym przyciskiem myszy dowolny folder w projekcie, aby utworzyć akcję wprowadzania danych. Lokalizacja folderu, który ma zostać utworzony, jest dowolna, ale zarządzaj nią zgodnie z projektem. Nazwa pliku jest również dowolna, ale tutaj InputActionSample jest .

Po dwukrotnym kliknięciu utworzonego pliku zostanie wyświetlone następujące okno.

Najpierw kliknij przycisk + w obszarze Mapy akcji, aby utworzyć mapę akcji. Jeśli zawartość operacji zmienia się w zależności od sceny, jako jednostka tworzenia, zostanie ona zdefiniowana w tej jednostce. Na przykład w przypadku przewijanej z boku gry akcji zawartość operacji zmienia się podczas akcji i w menu, więc utworzysz mapę akcji dla każdego z nich.

Tutaj, jako przykład, definiujemy akcję przewijania strony i nazywamy ją "SideScrollActionMap".

Następnie utwórz Akcje. Ponieważ jest to próbka, nie zrobię wielu z nich, ale tutaj utworzymy akcje "Move" dla ruchu i "Attack" dla ataku. Ponieważ jeden został już utworzony, zmień nazwę lub utwórz nowy, kliknij przycisk + w prawym górnym rogu i wprowadź go.

Najpierw skonfiguruj konfigurację przenoszenia. Kontroler zakłada, że używasz drążka, pada kierunkowego i kursora klawiatury. W przypadku przewijania w bok zdarzają się przypadki, w których używane są tylko lewa i prawa, ale tutaj zakładamy, że używasz czterech kierunków, rozważając skakanie z górnym i kucanie z w dół.

Po wybraniu opcji Przenieś po prawej stronie znajduje się opcja Typ akcji, więc ustaw ją na "Wartość".

Zobaczysz typ kontrolki poniżej, więc wybierz Vector2. Dzieje się tak, ponieważ góra i dół są przypisane do Y, a lewa i prawa są przypisane do X.

Następnie wybierz klucz, który chcesz przypisać do tego zdarzenia. Wybierz opcję Brak powiązania na środku i wybierz opcję Ścieżka po prawej stronie. Tutaj wybieramy GamePad LeftStick.

Wiąże to lewy drążek GamePada z ruchem.

Aby powiązać również inne kontrolery, wybierz "Dodaj powiązanie" z przycisku + po prawej stronie przycisku Move.

Teraz, gdy dodano Brak wiązania, przypisujemy Dpad do GamePada.

W ten sposób możesz dodać typ kontrolera, który chcesz obsługiwać, a także i drążki. Możliwe jest również ustawienie go specjalnie dla konkretnej konsoli do gier.

Drążki i Dpady to przyciski, które zakładają górę, dół, lewo i prawo, więc można je dodać za pomocą tego, ale w przypadku klawiatur wszystkie są pojedynczymi, więc nie ma definicji góra, dół, lewo i prawo. Aby ustawić klawiaturę w górę, w dół, w lewo lub w prawo, wybierz opcję Dodaj górę, dół, lewo, prawo kompozytowe za pomocą przycisku +.

Wektor 2D zostanie dodany i można go przypisać do każdego Góra, dół, Lewo, prawo, jak pokazano na poniższym rysunku.

Na przykład, jeśli używasz Strzałki w górę, ustaw "Strzałkę w górę" na klawiaturze. Nawiasem mówiąc, jeśli masz kłopoty ze znalezieniem klucza, możesz go łatwo wybrać, naciskając docelowy podczas klikania przycisku "Słuchaj".

W górę jest teraz ustawiona na strzałkę w górę.

Podobnie, ustaw Dół, Lewo i Prawo i gotowe.

Oczywiście można ustawić nie tylko kursora, ale także WASD.

Następnie skonfiguruj atak. Atak jest łatwy do przypisania, ponieważ jest to jeden przycisk. Najpierw wybierz opcję Atak i upewnij się, że Typ akcji to przycisk.

Następnie wybierz opcję Bez powiązania i wybierz przycisk, który chcesz przypisać ze ścieżki.

Jeśli chcesz dodać więcej, wybierz "Dodaj powiązanie" z przycisku +.

Dodaj tyle, ile potrzebujesz. Ponieważ jest traktowany jako przycisk, klawiaturę można ustawić w taki sam sposób, jak kontroler gier.

Po zakończeniu wszystkich ustawień kliknij "Zapisz zasób", aby zapisać. Możesz zamknąć to okno.

Na koniec z plikiem inputactions projektu (w tym przypadku utworzonym wcześniej plikiem InputActionSample) zaznacz "Generuj klasę C#" w inspektorze. Parametr zostanie dodany, ale kliknij przycisk "Zastosuj" tak, jak jest.

Spowoduje to wygenerowanie pliku skryptu o tej samej nazwie. Zawiera klasy, które są przydatne do korzystania z map akcji z programów.

Jak otrzymywać informacje wejściowe

Istnieje kilka sposobów otrzymywania danych wejściowych na podstawie mapy działań. Ta wskazówka wyjaśnia trzy wzorce, ale lepiej skupić się na jednym z nich podczas tworzenia gry. Jeśli używasz ich osobno, zarządzanie nimi będzie kłopotliwe.

Ponadto, jeśli używasz wielu metod odbioru danych wejściowych w jednej scenie, przetwarzanie może powodować konflikty wewnętrzne i nie działać poprawnie.

Odbieranie informacji wejściowych w oknie Wysyłanie wiadomości

Pierwszą metodą jest otrzymywanie informacji wejściowych w "Wysyłaniu wiadomości".

Tym razem chcę wyświetlić wprowadzone informacje w tekście, więc umieszczę obiekt tekstowy.

Ponadto, ponieważ ta wskazówka spróbuje uzyskać wiele informacji wejściowych, utworzymy pusty obiekt, aby ustawić komponent osobno. Nazwa może być dowolna.

Następnie dodaj składnik Wprowadzanie odtwarzacza do pustego obiektu. Wprowadzanie danych przez gracza jest ważnym elementem łączącym mapy akcji i skrypty.

W "Dodaj komponent" znajduje się "Wejście gracza" w kategorii "Wejście", więc dodaj je.

Po dodaniu komponentu wprowadzania danych odtwarzacza ustaw mapę akcji utworzoną w "Akcjach". Upuść go z projektu lub wybierz go z ikony + po prawej stronie.

Sprawdź, czy mapa domyślna jest mapą utworzoną na mapie działania.

Sprawdź, czy zachowanie to "Wyślij wiadomości".

Następnie utwórz skrypt. Nazwa pliku może być dowolna, ale tutaj InputSendMessage jest .

Skrypt wygląda tak:

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}";
  }
}
  • Obiekt ma dołączone wejście odtwarzacza, które ustawia Wyślij wiadomości
  • Dziedziczenie po MonoBehaviour

Jeśli warunki są spełnione, to jeśli zdefiniujesz metodę o nazwie "OnXXXXXXXX", Metoda docelowa zostanie wywołana po wykonaniu określonej operacji akcji. "XXXXXXXX" to nazwa akcji utworzonych na mapie działań. Tutaj utworzyliśmy akcje "Przenieś" i "Atak", więc nazwy metod to odpowiednio "OnMove" i "OnAttack".

OnMove Wpisaną kwotę można uzyskać z argumentu InputValue . Ponieważ Typ kontrolki jest ustawiony na "Wektor 2", wartość InputValue.Get<Vector2> wejściowa zostanie odebrana w formacie .

OnAttackInputValue.isPressed Możesz również sprawdzić, czy naciskasz.

Po zapisaniu skryptu dołącz go do obiektu zawierającego składnik Wprowadzanie danych przez odtwarzacza. Ustaw również obiekt tekstowy do wyświetlania.

Uruchom grę i spójrz. Tym razem zawarłem definicję gamepada i klawiatury, więc powinno działać bez względu na to, którą obsługujesz.

Jak widać po przeniesieniu, widać, że metoda jest wywoływana tylko wtedy, gdy nastąpi zmiana wartości w stosunku do poprzedniego stanu. Na przykład, przesuwając drążek w lewo, nazywa się go jednomyślnie, ale nie w lewo (- OnMove 1,0). OnMove Przycisk Atak reaguje tylko w momencie naciśnięcia, a jeśli zostanie naciśnięty i przytrzymany, metoda nie zostanie wywołana.

Dlatego uważam, że idealnym zastosowaniem nie jest przetwarzanie gry podczas wywoływania OnXXXXXXXX, ale zachowanie tylko zawartości wejściowej i wykorzystanie tych wartości w przetwarzaniu aktualizacji gry.

Nawiasem mówiąc, w bieżącym stanie nie jest wywoływany po zwolnieniu przycisku, więc nie można określić, kiedy OnAttack przycisk zostanie zwolniony. Aby na to zareagować, wybierz akcję ataku, która definiuje przycisk w ustawieniach mapy akcji i dodaj "Naciśnij" z "Interakcje". Następnie ustaw zachowanie wyzwalacza dodanej prasy na "Naciśnij i zwolnij" i zapisz go.

Po uruchomieniu widać, że jest wywoływany nawet OnAttack po zwolnieniu przycisku. isPressed false Ponieważ staje się , możliwe jest również określenie, czy jest to czas wydania.

Nawiasem mówiąc, usuń tę interakcję, ponieważ nie będzie ona używana w przyszłości.

Odbieranie danych wejściowych za pomocą zdarzeń Invoke Unity

Drugim sposobem odbierania danych wejściowych jest wywołanie zdarzeń jedności, więc spróbujmy tego. Jak wspomniano powyżej, użycie wielu metod wprowadzania danych może spowodować konflikt przetwarzania, więc jeśli włączone jest inne przetwarzanie, wyłącz je.

Najpierw umieść obiekt tekstowy tak, aby można było wyświetlić informacje wejściowe.

Wywołanie zdarzeń jedności powoduje utworzenie pustego obiektu, który wykonuje powiązane operacje.

Dodaj dane wejściowe > gracza do pustego obiektu.

Ustaw plik mapy akcji utworzony dla operacji (w tym przypadku InputActionSample) i ustaw utworzoną mapę akcji (w tym przypadku SideScrollActionMap) na Mapę domyślną. Ustaw zachowanie, aby wywołać zdarzenia Unity.

Utwórz skrypt. Nazwa jest arbitralna, ale w tym przypadku InputInvokeUnityEvents jest .

Skrypt wygląda tak:

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

Nazwa metodyOnMoveOnAttack, która jest wywoływana, gdy użytkownik wchodzi z nią w interakcję, to , tak jak w przypadku Wyślij wiadomości. W polu Wywołaj zdarzenia Unity można ustawić dowolną nazwę metody.

Po wywołaniu każdy z nich jest przekazywany InputAction.CallbackContext jako argument, dzięki czemu można uzyskać stan danych wejściowych. Jeśli ustawisz "wartość" w akcji, możesz ją otrzymać w metodzie, a jeśli ustawisz ReadValue ReadValueAsButton "przycisk", możesz ją odebrać w metodzie.

Po zapisaniu skryptu dołącz dane wejściowe odtwarzacza do ustawianego obiektu i ustaw wyświetlany obiekt tekstowy.

Następnie rozwiń "Event" i "Action Map Name (SideScrollActionMap)" w Input gracza, a powinieneś zobaczyć utworzone akcje "Move" i "Attack".

Najpierw kliknij przycisk + na Przenieś, aby go dodać.

Obiekt w lewym dolnym rogu jest Twoim własnym obiektem, a funkcja jest ustawiona na właśnie utworzoną OnMove metodę.

Skonfiguruj również zdarzenie Atak.

Uruchom grę, aby zobaczyć, jak to działa.

Zasadniczo jest wywoływany tylko wtedy, gdy zmienia się ta sama wartość, co Wyślij wiadomości, ale z jakiegoś powodu metoda może być wywoływana dwa razy w tym samym czasie. Nie znam przyczyny, ale myślę, że to prawdopodobnie dlatego, że proces startowy i proces ciągły działają w tym samym czasie. Myślę jednak, że nie ma problemu, jeśli zachowasz tylko wprowadzoną wartość jak w przypadku Send Messages i wykonasz właściwe przetwarzanie gry osobno w procesie aktualizacji.

Używanie automatycznie wygenerowanego skryptu do odbierania informacji wejściowych

W trzeciej sekcji opisano sposób uzyskiwania informacji wejściowych za pomocą skryptu wygenerowanego na podstawie pliku mapy działania.

Ponieważ istnieje możliwość konfliktów z innymi procesami przejęcia, należy wyłączyć inne procesy pozyskiwania.

Umieść obiekt tekstowy, aby wyświetlić informacje wejściowe.

Utwórz także pusty obiekt do pobierania informacji wejściowych. W tym artykule jest używany automatycznie wygenerowany skrypt, więc nie musisz dodawać danych wejściowych odtwarzacza.

Skrypt generowany automatycznie z mapy działania jest tylko biblioteką, więc utwórz oddzielny skrypt sterujący. Nazwa jest arbitralna, ale w tym przypadku InputScript jest .

Skrypt wygląda tak:

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

Zdefiniuj automatycznie wygenerowaną klasę InputActionSample z mapy akcji w polu. Ta klasa definiuje każdy zestaw akcji na mapie akcji i można ustawić zdarzenia, które są wywoływane podczas wykonywania tych akcji.

Awake W metodzie InputActionSample tworzona jest instancja i ustawiane jest zdarzenie wywołane w momencie wykonania akcji. Podczas OnMovewykonywania tych operacji wywoływana jest teraz metoda , OnAttack .

Ponieważ jednak ustawiamy zdarzenie tylko tutaj, musimy OnEnable wywołać metodę, gdy Enable jest wywoływana, aby włączyć mapę akcji.

Ponadto, ponieważ zachowanie użytkownika jest traktowane jako operacja globalna, Aby zapobiec OnDisable dodatkowemu działaniu mapy akcji po unieważnieniu tego obiektu, wywołujemy metodę w Disable metodzie, aby ją wyłączyć.

Po zapisaniu skryptu dołącz go do utworzonego pustego obiektu i ustaw obiekt tekstowy do wyświetlania.

Uruchom grę, aby zobaczyć, jak to działa.

Jak widać, metoda nie jest wywoływana, gdy OnMove operacja Move staje się (0, 0). Nie jestem pewien dlaczego, ale wydaje się, że wykonywane zdarzenie faktycznie zajmuje tylko to z włączonymi naciśnięciami.

Nawiasem mówiąc, jeśli nie ustawiłeś interakcji na mapie akcji dla ataku, nie zostanie on wywołany po OnAttack zwolnieniu przycisku.

Aby canceled sobie z tym poradzić, musisz skonfigurować wydarzenie. Jeśli nie chcesz wykonywać specjalnego przetwarzania w (0, 0), możesz wywołać metodę taką, jaka jest OnMove . To samo dotyczy Ataku.

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);   // 追加
}

Uruchom i sprawdź, czy pojawia się Move:(0, 0) lub Attack:False.