Behavor 속성중 Invoke C Sharp Events 옵션은 C# 스크립트에서 직접 이벤트를 연결해 사용하는 방식이다. Player Input컴포넌트를 사용할 수도 있고 Input Action에셋과 Player Inptu 컴포넌트 없이 모두 다 스크립트로 처리할 수도 있다.

사용을 위해 Behavior속성을 Invoke C Sharp Events로 변경한다.

PlayerCtrl 스크립트를 다음과 같이 변경한다. 

코드를 보면 동적으로 연결할 변수들을 선언한다.

private PlayerInput playerInput;  //invoke C# Events용 선언
private InputActionMap mainActionMap; //invoke C# Events용 선언
private InputAction moveAction; //invoke C# Events용 선언
private InputAction attackAction; //invoke C# Events용 선언

이 변수들에 맞는 컴포넌트및 ActionMap, Action등을 연결해준다

playerInput = GetComponent<PlayerInput>(); //PlayerInput 컴포넌트 연결
mainActionMap = playerInput.actions.FindActionMap("PlayerActions");
moveAction = mainActionMap.FindAction("Move");   //Move Action 추출
attackAction = mainActionMap.FindAction("Attack");  // Attack Action추출

이후 액션의 이벤트들이 발생했을때 실행할 로직을 람다식으로 지정한다.

moveAction.performed += ctx => { //중략};
moveAction.canceled += ctx => { //중략};
attackAction.performed += ctx => { //중략};

PlayerCtrl  전체 스크립트

#pragma warning disable IDE0051 //함수나 변구를 정의후 사용하지 않는 경고문구를 비활성화하는 구문

using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.InputSystem;  //Inputsystem사용을 위해 추가된 namespace

public class PlayerCtrl : MonoBehaviour {
    private Animator anim;
    private Vector3 moveDir;

    private PlayerInput playerInput;  //invoke C# Events용 선언
    private InputActionMap mainActionMap; //invoke C# Events용 선언
    private InputAction moveAction; //invoke C# Events용 선언
    private InputAction attackAction; //invoke C# Events용 선언

    void Start () {
        anim = GetComponent<Animator>();  //Animator컴포넌트를 연결
        playerInput = GetComponent<PlayerInput>();
        mainActionMap = playerInput.actions.FindActionMap("PlayerActions");
        moveAction = mainActionMap.FindAction("Move");   //Move Action 추출
        attackAction = mainActionMap.FindAction("Attack");  // Attack Action추출
        moveAction.performed += ctx => {
            Vector2 dir = ctx.ReadValue<Vector2>();
            moveDir = new Vector3(dir.x, 0, dir.y);
            anim.SetFloat("Movement", dir.magnitude);
        };
        moveAction.canceled += ctx => {
            moveDir = Vector3.zero;
            anim.SetFloat("Movement", 0.0f);
        };
        attackAction.performed += ctx => {
            Debug.Log("Attack by c# event");
            anim.SetTrigger("Attack");
        };
    }
    void Update () {
        if(moveDir != Vector3.zero) {
            transform.rotation = Quaternion.LookRotation(moveDir); //캐릭터회전
            transform.Translate(Vector3.forward * Time.deltaTime * 4.0f); //이동
        }
    }
#region SEND_MESSAGE
//중략
#endregion
#region UNITY_EVENTS
//중략
#endregion
}

Behavior - Invoke Unity Evnets옵션

Input Behavior를 Invoke Unity Events로 선택하면 다음과 같이 유저가 정의한 액션인 Move와 Attack이 Unity Event타입의 속성으로 표시된다. 일반적은 UI Button이벤트를 연결하는 방식이다. 공토으로 발생하는 3개의 이벤트도 같이 표시된다.

이상태에서는 스크립트에서 연결할 이벤트가 없으므로 PlayerCtrl을 다음과 같이 수정해준다.

#region SEND_MESSAGE #region UNITY_EVENTS 는 코드의 영역을 정의하는 전처리기 이다.

Invoke Unity Events를 선택했을때 넘어오는 파라미터는 InputAction.CallbackContex타입으로 입력값은 ReadValude<T>() 함수를 이용해 전달 받는다. Move Action을 Vector2로 정의했기 때문에 

Vector2 dir = ctx.ReadValue<Vector2>(); 와 같이 받아와야 한다. 나머지는 Send Messages 옵션과 동일하다

#pragma warning disable IDE0051 //함수나 변구를 정의후 사용하지 않는 경고문구를 비활성화하는 구문

using UnityEngine;
using UnityEngine.InputSystem;  //Inputsystem사용을 위해 추가된 namespace

public class PlayerCtrl : MonoBehaviour {
    private Animator anim;
    private Vector3 moveDir;

    void Start () {
        anim = GetComponent<Animator>();  //Animator컴포넌트를 연결
    }
    void Update () {
        if(moveDir != Vector3.zero) {
            transform.rotation = Quaternion.LookRotation(moveDir); //캐릭터회전
            transform.Translate(Vector3.forward * Time.deltaTime * 4.0f); //이동
        }
    }
#region SEND_MESSAGE
    void OnMove(InputValue value) {
        Vector2 dir = value.Get<Vector2>();
        moveDir = new Vector3(dir.x,0, dir.y);
        anim.SetFloat("Movement", dir.magnitude);
        Debug.Log($"Move = ({dir.x},{dir.y})");
    }
    void OnAttack() {
        Debug.Log("Attack");
        anim.SetTrigger("Attack");
    }
#endregion

#region UNITY_EVENTS
    public void OnMove(InputAction.CallbackContext ctx) {
        Vector2 dir = ctx.ReadValue<Vector2>();
        moveDir = new Vector3(dir.x,0,dir.y);
        anim.SetFloat("Movement", dir.magnitude);
    }
    public void OnAttack(InputAction.CallbackContext ctx) {
        Debug.Log($"ctx.phase={ctx.phase}");
        if (ctx.performed) {
            Debug.Log("Attack");
            anim.SetTrigger("Attack");
        }
    }
#endregion
}

스크립트에서 이벤트를 정의해 줬으니 이제 연결하자

Player Action 옆 ▶를 눌러 펼치면 Move(CallbackContex) List is Empty인데 +를 눌러준후 하이라키의 warrior를 끌어다 연결해준다. Attack도 끌어다 준다

이제 No Function을 눌러 OnMove와 OnAttack를 각각 연결해준다.

실행해보면 다음과 같이 3가지 상태가 차례로 호출되는 걸 확인할 수 있다.

 

Behavior - Send Message 옵션

Behavior 속성을 Send Messages로 선택하면 설정한 액션을 void On{액션명}() SendMessage함수를 이용해 호출한다. 

  • 특정 키가 들어오면, 특정한 함수를 자동으로 호출하는 방식
  • Broadcast Messages의 경우, 하위 계층에 있는 오브젝트들까지 제어를 할 수 있다.
  • 함수명이 "On + Actions name"으로 구성된다.
    • 앞에서 Move와 Attack액션을 정의했기 때문에 OnMove, OnAttack함수가 SendMessage를 통해 호출된다.

새로운 스크립트를 만들고 "PlayerCtrl"이라고 변경한다. Warrior에 연결해준다.

#pragma warning disable IDE0051 //함수나 변구를 정의후 사용하지 않는 경고문구를 비활성화하는 구문

using UnityEngine;
using UnityEngine.InputSystem;  //Inputsystem사용을 위해 추가된 namespace

public class PlayerCtrl : MonoBehaviour {
    // Start is called before the first frame update
    void OnMove(InputValue value) {
        Vector2 dir = value.Get<Vector2>();
        Debug.Log($"Move = ({dir.x},{dir.y})");
    }
    void OnAttack() {
        Debug.Log("Attack");
    }
}

이제 키입력을 통해 애니메이션과 이동 처리 로직을 구현한다. PlayerCtrl 스크립트를 다음과 같이 수정한다.

스크립트는 키입력의 이벤트를 통해 애니메이션을 컨트롤 한다.

애니메이션은 Idel, Run, Attack 3가지 뿐이고 방향은 rotation시킨다.

float Movement파라메터를 이용 Idle과 Run애니메이션을 선택하고 bool Attack이 Attack애니메이션을 트리거해준다

#pragma warning disable IDE0051 //함수나 변구를 정의후 사용하지 않는 경고문구를 비활성화하는 구문

using UnityEngine;
using UnityEngine.InputSystem;  //Inputsystem사용을 위해 추가된 namespace

public class PlayerCtrl : MonoBehaviour {
    private Animator anim;
    private Vector3 moveDir;

    void Start () {
        anim = GetComponent<Animator>();  //Animator컴포넌트를 연결
    }
    void Update () {
        if(moveDir != Vector3.zero) {
            transform.rotation = Quaternion.LookRotation(moveDir); //캐릭터회전
            transform.Translate(Vector3.forward * Time.deltaTime * 4.0f); //이동
        }
    }
    void OnMove(InputValue value) {
        Vector2 dir = value.Get<Vector2>();
        moveDir = new Vector3(dir.x,0, dir.y);
        anim.SetFloat("Movement", dir.magnitude);
        Debug.Log($"Move = ({dir.x},{dir.y})");
    }
    void OnAttack() {
        Debug.Log("Attack");
        anim.SetTrigger("Attack");
    }
}

실행해보면 WASD로 이동하고 Space키로 공격하는걸 확인할 수 있다.

 

Behavior 속성

Player Input의 Behavior는 Input Action에셋에 정의한 액션이 발생했을 때 코드의 함수를 어떻게 실행시킬 것인지를 결정하는 속성으로 다음 네 가지가 있다.

  • Send Messages : Player Input 컴포넌트가 있는 게임 오브젝트에 SendMessage함수를 이용해 호출
  • Broadcast Messages  :  BroadcastMessage함수를 이용 하위에 있는 게임오브젝트의 함수도 호출
  • Invoke Unity Events: 액션별로 이벤트 연결 인터페이스가 생성되고 각각 호출하려는 함수를 연결해 사용
  •  Invoke C Sharp Events  :  C# 스크립트에서 이벤트를 직접 연결해 사용
  • 위 방식들을 스크립트에서 사용하기 위해서는 다음과 같은 네임스페이스 적용이 필요

위 4가지 Behavior속성은 입력장치의 연결, 해지 변경사항에 대해 다음과 같은 이벤트를 기본으로 호출한다.

  • OnDeviceLost
  • OnDeviceRegained
  • OnControlsChanged

 

Player Input 컴포넌트는 Input Action에서 정의한 액션이 발생했을대 코드와 연결해 해당 로직을 실행시킬 수 있는 기능을 처리한다. 하이라키뷰의 Warrior를 선택해 인스펙터뷰의 Add component에서 Player Input 컴포넌트를 추가한다. 추가하면 Warrior발에 동그라미가 표시된다

Player Input Component의 Actions Item의  오른쪽 ◉를 눌러 브라우저에서 우리가 만든 MainAction을 선택한다. 

Default Schema는 나중에 빌드할 때, 타겟 플랫폼에 맞게 다음과 같이 설정 해주면 된다.

구동될 환경에 따라 플랫폼 선택. 본 글에서 MOBILE은 설정 따로 안 했으므로 우선 PC 선택

물론 Any로 설정하면 알아서 설정되긴 한다.

Default Map은 현재 Player Input 컴포넌트가 부착된 오브젝트가 "주인공 캐릭터"이므로, 아까 생성했던 "PlayerActions" Map을 선택해주면 된다.

 

그 외에도 예를 들어, 펫(Pet)을 조종하고 싶다면, "PetActions" Map을 생성해줘서 키 바인딩을 해주고, 펫 오브젝트에 부착하여 설정해주면 될 것이다.

해당 게임 오브젝트가 입력받을 Action Maps를 선택

이로써, 키 입력 셋팅은 다 끝이 났다.

이제 입력 받은 키 내용을 스크립트(script)에 전달하고, 그 값에 따라 처리를 하는 코드 작성 작업이 남았는데

글이 길어졌으므로 다음 글에서 다루도록 한다.

 



+ Recent posts