Usar mapas de ação para atribuir botões a comportamentos de jogo

Página atualizada :
Data de criação de página :

Ambiente de verificação

Windows
  • Janelas 11
Unity Editor
  • 25.3.2020F1
Pacote do sistema de entrada
  • 1.2.0

Pré-requisitos para esta dica

As configurações a seguir foram feitas com antecedência como premissa para a descrição desta dica.

Sobre os Mapas de Ação

Programas de entrada de usuários em teclados, mouses e gamepads basicamente afirmavam que uma determinada ação era executada quando um botão era pressionado. No mapa de ação, por exemplo, você pode definir a ação de "pular" e atribuir botões do controlador e teclas do teclado a ele. Como resultado, o programa só precisa descrever o processo quando uma ação específica é executada. Mesmo que você atribua um botão em outro controlador como uma reflexão posterior, você pode aplicá-lo sem alterar o programa operacional.

Criando um mapa de ação

Aqui, eu gostaria de criar um mapa de ação e exibir as informações de entrada do usuário no texto. Há várias maneiras de obter a entrada do usuário usando o Action Maps.

Clique com o botão direito do mouse em qualquer pasta no projeto para criar uma Ação de Entrada. A localização da pasta a ser criada é arbitrária, mas gerencie-a de acordo com o seu projeto. O nome do arquivo também é arbitrário, mas aqui InputActionSample está .

Quando você clica duas vezes no arquivo criado, a seguinte janela será exibida.

Primeiro, clique no botão + em Mapas de ação para criar um mapa de ação. Como uma unidade de criação, se o conteúdo da operação mudar dependendo da cena, ele será definido nessa unidade. Por exemplo, no caso de um jogo de ação de rolagem lateral, o conteúdo da operação muda durante a ação e no menu, então você criará um mapa de ação para cada um.

Aqui, como exemplo, definimos uma ação de rolagem lateral e a nomeamos "SideScrollActionMap".

Em seguida, crie Ações. Como é uma amostra, não farei muitas delas, mas aqui vamos criar ações de "Mover" para movimento e "Atacar" para ataque. Uma vez que um já foi criado, altere o nome ou crie um novo, clique no botão + no canto superior direito e digite-o.

Primeiro, configure a configuração Mover. O controlador pressupõe que você use as teclas do manípulo, do D-pad e do cursor do teclado. No caso de uma ação de rolagem lateral, há casos em que apenas esquerda e direita são usadas, mas aqui assumimos que você usa quatro direções considerando pular com a tecla superior e agachar-se com a tecla para baixo.

Quando você seleciona Mover, há uma seleção Tipo de ação à direita, então defina isso como "Valor".

Você verá o Tipo de Controle abaixo, então selecione Vector2. Isso ocorre porque a parte superior e inferior são atribuídas a Y, e a esquerda e a direita são atribuídas a X.

Em seguida, selecione a chave que você deseja atribuir a este evento. Selecione Sem vinculação no meio e selecione Caminho à direita. Aqui selecionamos o GamePad LeftStick.

Isso vincula o LeftStick do GamePad ao Move.

Para vincular outros controladores também, selecione "Adicionar ligação" no botão + à direita de Mover.

Agora que o No Binding foi adicionado, atribuímos um Dpad para o GamePad.

Desta forma, você pode adicionar o tipo de controlador que deseja suportar, bem como as teclas e varas. Também é possível configurá-lo especificamente para um console de jogos específico.

Sticks e Dpads são botões que assumem para cima, para baixo, para a esquerda e para a direita, então eles podem ser adicionados com isso, mas no caso dos teclados, eles são todos teclas únicas, então não há definição para cima, baixo, esquerda e direita. Para configurar o teclado para cima, para baixo, para a esquerda ou para a direita, selecione Adicionar composto esquerdo direito no botão +.

Um vetor 2D será então adicionado e você pode atribuí-lo a cada Up Down Left Right, como mostrado na figura abaixo.

Por exemplo, se você usar Up, configure "Seta para cima" no teclado. By the way, se você é problemático para encontrar uma chave, você pode facilmente selecioná-lo pressionando a tecla de destino enquanto clica no botão "Ouvir".

Up agora está definido como Up Arrow.

Da mesma forma, defina Baixo, Esquerda e Direita e pronto.

Claro, não só as teclas do cursor, mas também o WASD podem ser definidos.

Em seguida, configure o Ataque. O ataque é fácil de atribuir porque é um único botão. Primeiro, selecione Atacar e verifique se o Tipo de Ação é um botão.

Em seguida, selecione Sem vinculação e selecione o botão que deseja atribuir no Caminho.

Se você quiser adicionar mais, selecione "Adicionar vinculação" no botão +.

Adicione quantos você precisar. Como é tratado como um botão, o teclado pode ser configurado da mesma forma que um controlador de jogo.

Quando todas as configurações estiverem concluídas, clique em "Salvar ativo" para salvar. Você pode fechar esta janela.

Finalmente, com o arquivo inputactions do projeto (neste caso, o arquivo InputActionSample criado anteriormente), marque "Gerar classe C#" no inspetor. O parâmetro será adicionado, mas clique no botão "Aplicar" como está.

Isso gerará um arquivo de script com o mesmo nome. Ele contém classes que são úteis para usar mapas de ação de programas.

Como receber informações de entrada

Há várias maneiras de receber entrada com base em um mapa de ação. Essa dica explica três padrões, mas é melhor focar em um deles ao realmente fazer um jogo. Se você usá-los separadamente, será problemático para gerenciar.

Além disso, se você usar vários métodos de recebimento de entrada em uma única cena, o processamento pode entrar em conflito internamente e não funcionar corretamente.

Receber informações de entrada em Enviar mensagens

O primeiro método aqui é como receber informações de entrada em "Enviar mensagens".

Desta vez, quero exibir as informações inseridas no texto, então colocarei um objeto de texto.

Além disso, como essa dica tentará obter várias informações de entrada, criaremos um objeto vazio para definir o componente separadamente. O nome pode ser qualquer coisa.

Em seguida, adicione um componente Entrada do Player ao objeto vazio. A Entrada do Jogador é um componente importante para conectar mapas de ação e scripts.

Em "Adicionar componente", há "Entrada do jogador" na categoria "Entrada", então adicione-a.

Depois que o componente Entrada do Player for adicionado, defina o mapa de ação que você criou em "Ações". Solte-o do projeto ou selecione-o no ícone + à direita.

Verifique se o Mapa Padrão é o que você criou no mapa de ações.

Verifique se o comportamento é "Enviar mensagens".

Em seguida, crie um script. O nome do arquivo pode ser qualquer coisa, mas aqui InputSendMessage está .

O script tem a seguinte aparência:

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}";
  }
}
  • O objeto tem uma entrada do Player anexada que define Enviar mensagens
  • Herdando do MonoBehaviour

Se as condições forem atendidas, se você definir um método chamado "OnXXXXXXXX", O método de destino será chamado quando a operação de ação especificada for executada. "XXXXXXXX" é o nome das Ações criadas no mapa de ações. Aqui, criamos ações "Move" e "Attack", então os nomes dos métodos são "OnMove" e "OnAttack", respectivamente.

OnMove Você pode obter o valor inserido a partir do argumento InputValue de . Como o Tipo de Controle está definido como "Vetor 2", o valor InputValue.Get<Vector2> de entrada será recebido em .

OnAttackInputValue.isPressed Você pode obter se você está pressionando também.

Depois de salvar o script, anexe-o a um objeto que tenha um componente de entrada do player. Defina o objeto de texto para exibição também.

Execute o jogo e dê uma olhada. Desta vez, eu incluí a definição do gamepad e teclado, então ele deve funcionar não importa qual você opera.

Como você pode ver ao movê-lo, você pode ver que o método é chamado somente quando há uma alteração no valor do estado anterior. Por exemplo, ao mover o bastão para a esquerda, ele é chamado de pensamento único, mas não para a esquerda (- OnMove 1,0). OnMove O botão Ataque também responde apenas no momento em que é pressionado e, se for pressionado e mantido, o método não é chamado.

Portanto, acho que o uso ideal não é realizar o processamento do jogo quando o OnXXXXXXXX é chamado, mas manter apenas o conteúdo de entrada e usar esses valores no processamento de atualização do jogo.

A propósito, no estado atual, ele não é chamado quando o botão é liberado, portanto, não é possível determinar quando OnAttack o botão é liberado. Para responder a isso, selecione a ação Ataque que define o botão nas configurações do mapa de ação e adicione "Pressionar" em "Interações". Depois disso, defina o comportamento de gatilho da imprensa adicionada como "Pressione e libere" e salve-o.

Quando executado, você pode ver que é chamado mesmo OnAttack quando o botão é liberado. isPressed false Uma vez que se torna , também é possível determinar se é o momento da liberação.

A propósito, exclua essa interação porque ela não será usada no futuro.

Receba entrada com Invoke Unity Events

Uma segunda maneira de receber entrada é Invocar Eventos Unity, então vamos tentar isso. Como mencionado acima, o uso de vários métodos de entrada pode causar processamento conflitante, portanto, se outro processamento estiver habilitado, desative-o.

Primeiro, coloque o objeto de texto para que as informações de entrada possam ser exibidas.

Invoke Unity Events cria um objeto vazio que executa operações relacionadas.

Adicione Entrada > Player Input ao objeto vazio.

Defina o arquivo de mapa de ação criado para Ações (neste caso, InputActionSample) e defina o Mapa de Ação criado (neste caso, SideScrollActionMap) como Mapa Padrão. Defina Comportamento para invocar eventos Unity.

Crie um script. O nome é arbitrário, mas neste caso InputInvokeUnityEvents é .

O script tem a seguinte aparência:

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

O nome OnMoveOnAttack do método que é chamado quando o usuário interage com ele é , como no caso de Enviar mensagens. Em Invocar eventos Unity, você pode definir esse nome de método como desejar.

Quando cada um é chamado, ele é passado como um InputAction.CallbackContext argumento, para que você possa obter o status de entrada a partir daí. Se você definir um "valor" na ação, você pode recebê-lo no método, e se você definir ReadValueAsButton um "botão", você ReadValue pode recebê-lo no método.

Depois de salvar o script, anexe a Entrada do Player ao objeto que você está definindo e defina o objeto de texto de exibição.

Em seguida, expanda "Evento" e "Nome do Mapa de Ação (SideScrollActionMap)" na Entrada do Jogador e você verá as ações "Mover" e "Atacar" que você criou.

Primeiro, clique no botão + em Mover para adicioná-lo.

O objeto no canto inferior esquerdo é seu próprio objeto e a função é definida como o método que você acabou de criar OnMove .

Configure o evento Attack também.

Execute o jogo para ver como ele funciona.

Basicamente, ele é chamado apenas quando o mesmo valor de Send Messages é alterado, mas por algum motivo o método pode ser chamado duas vezes ao mesmo tempo. Não sei a causa, mas acho que é provavelmente porque o processo inicial e o processo contínuo estão sendo executados ao mesmo tempo. No entanto, acho que não há problema se você manter apenas o valor inserido como no caso de Enviar Mensagens e executar o processamento real do jogo separadamente no processo de atualização.

Usar um script gerado automaticamente para receber informações de entrada

A terceira seção descreve como obter informações de entrada usando um script gerado a partir de um arquivo de mapa de ação.

Uma vez que existe a possibilidade de conflitos com outros processos de aquisição, desative outros processos de aquisição.

Coloque um objeto de texto para exibir as informações de entrada.

Além disso, crie um objeto vazio para recuperar informações de entrada. Este artigo usa um script gerado automaticamente, portanto, você não precisa adicionar a Entrada do Player.

O script gerado automaticamente a partir do mapa de ação é apenas uma biblioteca, portanto, crie um script de controle separado. O nome é arbitrário, mas neste caso InputScript é .

O script tem a seguinte aparência:

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

Defina uma classe InputActionSample gerada automaticamente a partir do mapa de ação no campo. Essa classe define cada conjunto de ações no mapa de ações e você pode definir os eventos que são chamados quando essas ações são executadas.

Awake No método, InputActionSample uma instância de é criada e o evento chamado no momento da ação é definido. Quando OnMovevocê executa essas operações, o método , OnAttack agora é chamado.

No entanto, como só definimos o evento aqui, OnEnable precisamos chamar o método quando Enable é chamado para habilitar o mapa de ação.

Além disso, como o comportamento de entrada do usuário é tratado como uma operação global, Para impedir que o mapa de ação faça mais depois que OnDisable esse objeto for invalidado, chamamos o método no Disable método para desabilitá-lo.

Depois de salvar o script, anexe-o ao objeto vazio criado e defina o objeto de texto para exibição.

Execute o jogo para ver como ele funciona.

Como você pode ver, o método não é chamado quando OnMove a operação Move se torna (0, 0). Não sei bem porquê, mas parece que o evento realizado só leva realmente aquele com pressionamentos de tecla ativados.

A propósito, se você não tiver definido Interações no mapa de ação para Ataque, ele não será chamado quando OnAttack você soltar o botão.

Para canceled lidar com isso, você precisa configurar um evento. Se você não deseja executar o processamento especial em (0, 0), você pode chamar o método como ele é OnMove . O mesmo vale para o 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);   // 追加
}

Execute e verifique se Move:(0, 0) ou Attack:False aparece.