작업 맵을 사용하여 게임 동작에 단추 할당Use action maps to assign buttons to game behavior

페이지 업데이트 :
페이지 생성 날짜 :

검증 환경

윈도우
  • 윈도우 11
Unity 에디터
  • 2020.3.25f1
입력 시스템 패키지
  • 1.2.0

이 팁의 전제 조건

이 팁에 대한 설명의 전제로 다음 설정이 미리 이루어졌습니다.

작업 맵 정보

키보드, 마우스 및 게임 패드의 사용자 입력 프로그램은 기본적으로 버튼을 눌렀을 때 특정 동작이 수행되었다고 명시했습니다. 예를 들어 액션 맵에서 "점프"동작을 정의하고 컨트롤러 버튼과 키보드 키를 할당 할 수 있습니다. 결과적으로 프로그램은 특정 작업이 수행될 때의 프로세스만 설명하면 됩니다. 나중에 다른 컨트롤러에 버튼을 할당하더라도 운영 프로그램을 변경하지 않고 적용 할 수 있습니다.

작업 맵 만들기

여기서는 액션 맵을 만들고 사용자의 입력 정보를 텍스트에 표시하고 싶습니다. Action Maps를 사용하여 사용자 입력을 가져오는 방법에는 여러 가지가 있습니다.

프로젝트의 폴더를 마우스 오른쪽 버튼으로 클릭하여 입력 액션을 만듭니다. 생성 할 폴더의 위치는 임의로 정해 져 있습니다 만, 프로젝트에 맞게 관리하십시오. 파일 이름도 임의적이지만 여기에 InputActionSample 있습니다.

생성된 파일을 더블 클릭하면 다음과 같은 창이 뜹니다.

먼저 Action Maps에서 + 버튼을 클릭하여 Action Map을 만듭니다. 생성 단위로서 장면에 따라 조작 내용이 바뀌면 그 단위로 정의됩니다. 예를 들어, 횡스크롤 액션 게임의 경우, 액션이 진행되는 동안이나 메뉴에서 조작의 내용이 변경되기 때문에, 각각에 대한 액션 맵을 작성하게 됩니다.

여기서는 횡스크롤 작업을 정의하고 이름을 "SideScrollActionMap"으로 지정합니다.

그런 다음 작업을 만듭니다. 샘플이기 때문에 많이 만들지는 않겠지만 여기서는 이동을 위한 "이동" 동작과 공격을 위한 "공격"을 만듭니다. 이미 생성되었으므로 이름을 변경하거나 새로 만들고 오른쪽 상단의 + 버튼을 클릭하여 입력하십시오.

먼저 이동 구성을 구성합니다. 컨트롤러는 스틱, 방향 패드 및 키보드 커서 키를 사용한다고 가정합니다. 횡스크롤 동작의 경우 왼쪽과 오른쪽만 사용하는 경우도 있습니다만, 여기서는 위쪽 키로 점프하고 아래쪽 키로 웅크리는 것을 고려한 4가지 방향을 사용하는 것으로 가정합니다.

이동을 선택하면 오른쪽에 작업 유형 선택 항목이 있으므로 이를 "값"으로 설정합니다.

아래에 컨트롤 유형이 표시되므로 Vector2를 선택합니다. 이는 위쪽과 아래쪽이 Y에 할당되고 왼쪽과 오른쪽이 X에 할당되기 때문입니다.

그런 다음 이 이벤트에 할당할 키를 선택합니다. 중간에서 바인딩 없음을 선택하고 오른쪽에서 경로를 선택합니다. 여기에서 GamePad LeftStick을 선택합니다.

이렇게 하면 게임 패드의 LeftStick이 이동에 바인딩됩니다.

다른 컨트롤러도 바인딩하려면 Move 오른쪽의 + 버튼에서 "Add Binding"을 선택합니다.

이제 바인딩 없음이 추가되었으므로 게임 패드에 대한 Dpad를 할당합니다.

이런 식으로 지원하려는 컨트롤러 유형과 키와 스틱을 추가할 수 있습니다. 특정 게임 콘솔에 맞게 특별히 설정할 수도 있습니다.

스틱과 디패드는 위, 아래, 왼쪽, 오른쪽을 가정한 버튼이므로 이것으로 추가할 수 있지만 키보드의 경우 모두 단일 키이므로 위, 아래, 왼쪽, 오른쪽에 대한 정의가 없습니다. 키보드를 위, 아래, 왼쪽 또는 오른쪽으로 설정하려면 + 버튼에서 [위로, 아래로, 왼쪽, 오른쪽, 합성]을 선택합니다.

그러면 2D 벡터가 추가되고 아래 그림과 같이 각 위, 아래, 왼쪽, 오른쪽에 할당할 수 있습니다.

예를 들어 Up을 사용하는 경우 키보드에서 "위쪽 화살표"를 설정합니다. 덧붙여서 키를 찾기가 번거롭다면 "듣기" 버튼을 클릭하면서 대상 키를 눌러 쉽게 선택할 수 있습니다.

이제 위쪽 화살표가 위쪽 화살표로 설정됩니다.

마찬가지로 Down, Left 및 Right를 설정하면 완료됩니다.

물론 커서 버튼뿐만 아니라 WASD도 설정할 수 있습니다.

다음으로 공격을 구성합니다. 공격은 버튼 하나이기 때문에 할당하기 쉽습니다. 먼저 공격을 선택하고 작업 유형이 버튼인지 확인합니다.

그런 다음 바인딩 없음을 선택하고 경로에서 할당할 단추를 선택합니다.

더 추가하려면 + 버튼에서 "바인딩 추가"를 선택합니다.

필요한 만큼 추가합니다. 버튼으로 취급되기 때문에 게임 컨트롤러와 같은 방식으로 키보드를 설정할 수 있습니다.

모든 설정이 완료되면 "자산 저장"을 클릭하여 저장합니다. 이 창을 닫을 수 있습니다.

마지막으로, 프로젝트의 inputactions 파일(이 경우 이전에 만든 InputActionSample 파일)을 사용하여 인스펙터에서 "Generate C# Class"를 선택합니다. 매개 변수가 추가되지만 그대로 "적용"버튼을 클릭합니다.

이렇게 하면 동일한 이름의 스크립트 파일이 생성됩니다. 여기에는 프로그램에서 작업 맵을 사용하는 데 유용한 클래스가 포함되어 있습니다.

입력 정보를 받는 방법

작업 맵에 따라 입력을 받는 방법에는 여러 가지가 있습니다. 이 팁은 세 가지 패턴을 설명하지만 실제로 게임을 만들 때 그 중 하나에 집중하는 것이 좋습니다. 따로 사용하면 관리가 번거로울 것입니다.

또한 단일 장면에서 여러 입력 수신 방법을 사용하는 경우 처리가 내부적으로 충돌하여 제대로 작동하지 않을 수 있습니다.

메시지 보내기에서 입력 정보 받기

첫 번째 방법은 "메시지 보내기"에서 입력 정보를받는 방법입니다.

이번에는 입력 한 정보를 텍스트에 표시하고 싶기 때문에 텍스트 객체를 배치합니다.

또한 이 팁은 여러 입력 정보를 얻으려고 하므로 구성 요소를 별도로 설정하기 위해 빈 개체를 만듭니다. 이름은 무엇이든 될 수 있습니다.

그런 다음 Player Input 구성 요소를 빈 객체에 추가합니다. 플레이어 입력은 액션 맵과 스크립트를 연결하는 데 중요한 구성 요소입니다.

"Add Component"의 "Input" 카테고리에 "Player Input"이 있으니 추가하세요.

Player Input 컴포넌트가 추가되면 "Actions"에서 생성한 액션 맵을 설정합니다. 프로젝트에서 드롭하거나 오른쪽의 + 아이콘에서 선택합니다.

Default Map(기본 맵)이 작업 맵에서 만든 맵인지 확인합니다.

동작이 "메시지 보내기"인지 확인합니다.

그런 다음 스크립트를 만듭니다. 파일 이름은 무엇이든 될 수 있지만 여기에 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}";
  }
}
  • 객체에는 Send Messages를 설정하는 Player Input이 연결되어 있습니다
  • MonoBehaviour에서 상속하기

조건이 충족되면 "OnXXXXXXXX"라는 메서드를 정의하면 대상 메서드는 지정된 작업 작업이 수행될 때 호출됩니다. "XXXXXXXX"는 작업 맵에서 만든 작업의 이름입니다. 여기서는 "Move" 및 "Attack" 액션을 생성했으므로 메서드 이름은 각각 "OnMove" 및 "OnAttack"입니다.

OnMove 의 인수 InputValue 에서 입력된 금액을 얻을 수 있습니다. Control Type이 "Vector 2"로 설정되어 있으므로 입력 값은 InputValue.Get<Vector2> 에 수신됩니다.

OnAttackInputValue.isPressed 당신은 당신이 누르고 있는지 여부도 얻을 수 있습니다.

스크립트를 저장한 후 Player Input 구성 요소가 있는 객체에 연결합니다. 표시할 문자 객체도 설정합니다.

게임을 실행하고 살펴보십시오. 이번에는 게임 패드와 키보드의 정의를 포함 시켰으므로 어떤 것을 사용하든 작동해야합니다.

이동하면 알 수 있듯이 이전 상태에서 값이 변경된 경우에만 메서드가 호출되는 것을 볼 수 있습니다. 예를 들어, 스틱을 왼쪽으로 움직일 때 단독으로 호출되지만 왼쪽(- OnMove 1,0)은 호출되지 않습니다. OnMove Attack 버튼도 누르는 순간에만 반응하며, 길게 누르면 메서드가 호출되지 않습니다.

따라서 OnXXXXXXXX가 호출되었을 때 게임 처리를 수행하는 것이 아니라 입력 내용만 유지하고 그 값을 게임의 업데이트 처리에 사용하는 것이 이상적인 사용법이라고 생각합니다.

덧붙여서 현재 상태에서는 버튼에서 손을 떼면 호출되지 않기 때문에 버튼이 언제 해제되는지 알 OnAttack 수 없습니다. 이에 대응하려면 액션 맵 설정에서 버튼을 정의하는 공격 액션을 선택하고 "상호 작용"에서 "누르기"를 추가하십시오. 그런 다음 추가된 Press의 Trigger Behavior를 "Press And Release"로 설정하고 저장합니다.

실행하면 버튼에서 손을 떼어도 호출 OnAttack 되는 것을 볼 수 있습니다. isPressed false 가 되기 때문에, 발매 시기인지 여부를 판단하는 것도 가능하다.

덧붙여서, 이 인터랙션은 앞으로 사용되지 않으므로 삭제하십시오.

Unity 이벤트 호출(Invoke Unity Events)을 사용하여 입력 받기

입력을 받는 두 번째 방법은 Unity 이벤트 호출(Invoke Unity Events)이니 시도해 보겠습니다. 위에서 언급했듯이 여러 입력 방법을 사용하면 처리가 충돌할 수 있으므로 다른 처리가 활성화된 경우 비활성화하십시오.

먼저 입력 정보를 표시할 수 있도록 텍스트 개체를 배치합니다.

Unity 이벤트 호출은 관련 작업을 수행하는 빈 오브젝트를 생성합니다.

빈 오브젝트에 Input > Player Input을 추가합니다.

Actions에 대해 만든 작업 맵 파일(이 경우 InputActionSample)을 설정하고 만든 작업 맵(이 경우 SideScrollActionMap)을 Default Map으로 설정합니다. Unity 이벤트를 호출하도록 Behavior를 설정합니다.

스크립트를 만듭니다. 이름은 임의적이지만 이 경우에는 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 메시지 보내기의 경우와 마찬가지로 입니다. Unity 이벤트 호출에서 이 메서드 이름을 원하는 대로 설정할 수 있습니다.

각각이 호출되면 인수로 InputAction.CallbackContext 전달되므로 거기에서 입력 상태를 가져올 수 있습니다. 액션에 "값"을 설정하면 메소드에서 받을 수 있고 ReadValue , "버튼"을 설정하면 ReadValueAsButton 메소드에서 받을 수 있습니다.

스크립트를 저장한 후 설정 중인 객체에 플레이어 입력을 첨부하고 표시 텍스트 객체를 설정합니다.

그런 다음 플레이어 입력에서 "이벤트"와 "액션 맵 이름(SideScrollActionMap)"을 펼치면 생성한 "이동" 및 "공격" 액션이 표시됩니다.

먼저 이동에서 + 버튼을 클릭하여 추가합니다.

왼쪽 아래 모서리에 있는 개체는 사용자 고유의 개체이며 Function은 방금 만든 OnMove 메서드로 설정됩니다.

공격 이벤트도 구성합니다.

게임을 실행하여 어떻게 작동하는지 확인하십시오.

기본적으로 메시지 보내기와 같은 값이 바뀔 때만 호출되지만, 어떤 이유에서인지 메서드가 동시에 두 번 호출될 수 있습니다. 원인은 모르겠지만 아마도 시작 프로세스와 연속 프로세스가 동시에 실행되고 있기 때문이라고 생각합니다. 다만, Send Messages의 경우처럼 입력된 값만 유지하고, Update 과정에서 실제 게임 처리를 별도로 수행한다면 문제가 없다고 생각합니다.

자동 생성된 스크립트를 사용하여 입력 정보 수신

세 번째 섹션에서는 작업 맵 파일에서 생성된 스크립트를 사용하여 입력 정보를 가져오는 방법에 대해 설명합니다.

다른 획득 프로세스와 충돌할 가능성이 있으므로 다른 획득 프로세스를 비활성화하십시오.

입력 정보를 표시할 텍스트 객체를 배치합니다.

또한 입력 정보를 검색하기 위해 빈 개체를 만듭니다. 이 문서에서는 자동 생성된 스크립트를 사용하므로 플레이어 입력을 추가할 필요가 없습니다.

작업 맵에서 자동으로 생성된 스크립트는 라이브러리일 뿐이므로 별도의 제어 스크립트를 만듭니다. 이름은 임의적이지만 이 경우에는 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 만 이벤트를 설정했기 때문에 작업 맵을 활성화하기 위해 when Enable 메서드가 호출되어야 합니다.

또한 사용자의 입력 동작이 전역 작업으로 처리되기 때문에, 이 개체가 무효화된 후 작업 맵이 추가 작업을 수행하지 않도록 OnDisable 하려면 메서드에서 Disable 메서드를 호출하여 비활성화합니다.

스크립트를 저장한 후 만든 빈 개체에 첨부하고 표시할 텍스트 개체를 설정합니다.

게임을 실행하여 어떻게 작동하는지 확인하십시오.

보시다시피 Move 작업이 (0, 0)이 될 때 OnMove 메서드가 호출되지 않습니다. 이유는 모르겠지만 수행 된 이벤트는 실제로 키 입력이 활성화 된 이벤트 만 사용하는 것 같습니다.

덧붙여서 액션 맵에서 Attack에 대한 상호 작용을 설정하지 않은 경우 버튼에서 손을 뗄 때 OnAttack 호출되지 않습니다.

이를 처리하려면 canceled 이벤트를 설정해야 합니다. (0, 0)에서 특수 처리를 수행하지 않으려면 메서드를 그대로 OnMove 호출할 수 있습니다. 공격도 마찬가지입니다.

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가 나타나는지 확인합니다.