오늘의 학습 키워드

InputSystem(SendMessage, Invoke Unity Events)

 

공부한 내용

SendMessage vs Invoke Unity Events

SendMessage 특징

- InputAction으로 지정한 Action들의 이름 앞On이 붙은 함수를 호출하며 ex) OnMove

- InputValue를 매개변수로 받는다. (코드에서 누른 시점, 누르고 있는 시점, 뗀 시점 제어 불가)

void OnMove(InputValue value)
{
    Vector2 arrowInput = value.Get<Vector2>();
    Debug.Log(arrowInput);
    CallMoveAction(arrowInput);
}

void OnLook(InputValue value)
{
    Vector2 mousePos = value.Get<Vector2>();
    Vector2 mousePosInWorld = _mainCam.ScreenToWorldPoint(new Vector3(mousePos.x, mousePos.y, transform.position.z));

    
    Vector2 direction = (mousePosInWorld - (Vector2)transform.position).normalized;

    CallLookAction(direction);
}

void OnAttack(InputValue value)
{
    IsAttacking = value.isPressed;
}

 

Invoke Unity Events 특징

- 함수명에 상관 없이 Unity Event인스펙터에서 등록이 가능하고

- InputAction.CallbackContext매개변수로 받아 콜백 시점을 정할 수 있다. ex) performed, canceled

private void Start()
{
    var inputTypes = (InputType[])Enum.GetValues(typeof(AnimState));

    foreach (var inputAction in _playerInput.actions)
    {
        InputType state = Array.Find(inputTypes, x => x.ToString() == inputAction.name);

        switch (state)
        {
            case InputType.Move:
                inputAction.performed += OnMove;
                inputAction.canceled += OnMove;
                break;
            case InputType.Look:
                inputAction.performed += OnLook;
                break;
            case InputType.Attack:
                inputAction.performed += OnAttack;
                break;
        }
    }
}

void OnMove(InputAction.CallbackContext context)
{
    Vector2 arrowInput = context.ReadValue<Vector2>();
    Debug.Log(arrowInput);
    CallMoveAction(arrowInput);
}

void OnLook(InputAction.CallbackContext context)
{
    Vector2 mousePos = context.ReadValue<Vector2>();
    Vector2 mousePosInWorld = _mainCam.ScreenToWorldPoint(new Vector3(mousePos.x, mousePos.y, transform.position.z));

    // atan을 구하기 위해 normalized
    Vector2 direction = (mousePosInWorld - (Vector2)transform.position).normalized;

    CallLookAction(direction);
}

void OnAttack(InputAction.CallbackContext context)
{
    IsAttacking = context.performed;
}

 

애니메이션 루프 탈출

애니메이션 Attack 루프를 탈출 못하는 버그에 걸렸다.

한 번 클릭해도 다른 입력(이동)이 들어오면 Attack이 멈추지 않았다.

해결 방안으로 코루틴을 돌아 애니메이션이 끝나면 이동 속도에 따라 해당 애니메이션으로 빠져나가게 만들었다.

private void SetState(AnimState state)
{
    _state = state;

    switch (_state)
    {
        case AnimState.Idle:
            _animator.CrossFade(PlayerManager.Instance.AnimToHash.ANIM_IDLE, 0.3f);
            break;
        case AnimState.Walk:
            _animator.CrossFade(PlayerManager.Instance.AnimToHash.ANIM_WALK, 0.3f);
            break;
        case AnimState.Preslide:
            _animator.CrossFade(PlayerManager.Instance.AnimToHash.ANIM_PRESLIDE, 0.3f);
            break;
        case AnimState.Attack:
            _animator.Play(PlayerManager.Instance.AnimToHash.ANIM_ATTACK);
            StartCoroutine(CoWaitForCurrentAnimation(PlayerManager.Instance.AnimToHash.ANIM_ATTACK));
            break;
        case AnimState.Jump:
            _animator.Play(PlayerManager.Instance.AnimToHash.ANIM_JUMP);
            StartCoroutine(CoWaitForCurrentAnimation(PlayerManager.Instance.AnimToHash.ANIM_JUMP));
            break;
    }
}

private IEnumerator CoWaitForCurrentAnimation(int hashValue)
{
    bool isAnimationProgress = true;
    
    // 애니메이션이 Attack인지 확인 이후
    // 해당 애니메이션 현재 시간을 normalize 한 값이 0.9보다 클 때 탈출
    while (isAnimationProgress)
    {
        if (_animator.GetCurrentAnimatorStateInfo(0).shortNameHash == hashValue)
        {
            isAnimationProgress = _animator.GetCurrentAnimatorStateInfo(0).normalizedTime < 0.9f;
        }
        
        yield return null;
    }
    
    if (PlayerManager.Instance.Velocity.sqrMagnitude > 0)
    {
        SetState(AnimState.Walk);
    }
    else
    {
        SetState(AnimState.Idle);
    }
}

 

ReadOnly 초기화

readonly 초기 Setter생성자에서는 초기화가 된다.

- Setter는 선언할 때 같이 쓰는 것 됨

using System;
using UnityEngine;

public class AnimNameHash
{
    private const string ANIM_FRONT = "penguin_";

    [Header("AnimToHashValue")]
    public readonly int ANIM_IDLE;
    public readonly int ANIM_WALK;
    public readonly int ANIM_ATTACK;
    public readonly int ANIM_PRESLIDE;
    public readonly int ANIM_JUMP;

    public AnimNameHash()
    {
        var states = Enum.GetValues(typeof(AnimState));
        foreach (var state in states)
        {
            string stateName = ANIM_FRONT + state.ToString();

            switch (state)
            {
                case AnimState.Idle:
                    ANIM_IDLE = Animator.StringToHash(stateName);
                    break;
                case AnimState.Walk:
                    ANIM_WALK = Animator.StringToHash(stateName);
                    break;
                case AnimState.Preslide:
                    ANIM_PRESLIDE = Animator.StringToHash(stateName);
                    break;
                case AnimState.Attack:
                    ANIM_ATTACK = Animator.StringToHash(stateName);
                    break;
                case AnimState.Jump:
                    ANIM_JUMP = Animator.StringToHash(stateName);
                    break;
            }
        }
    }
}

 

오늘의 회고

 오늘은 유니티의 Input System에 대해 알아봤다. 강의에서 배운 SendMessage는 채팅 기능과 같이 바로 등록시켜줘야 하는 경우에 쓰면 좋고 Invoke Unity Events는 서버에서 다른 경로로 오는 데이터를 모두 받아야 실행할 수 있는 작업이 있을 때 사용하면 좋다고 한다. 나의 경우는 강의에서 이미 SendMessage를 사용해봤으니 이번엔 호출 시점을 정해줄 수 있는 Invoke Unity Events를 사용하기로 했다.

 내일도 오늘 작업하던 개인 과제를 더 진행할 생각이다. 내일 거의 완성을 해야 목요일까지 제출이 가능할 것 같아 열심히 해봐야겠다. 내일도 파이팅!

 

참고 :

https://docs.unity3d.com/Packages/com.unity.inputsystem@1.8/api/UnityEngine.InputSystem.html

 

Namespace UnityEngine.InputSystem | Input System | 1.8.0-pre.1

Namespace UnityEngine.InputSystem Classes Input device representing an accelerometer sensor. Input device representing the ambient air temperature measured by the device playing the content. Input device representing an attitude sensor. A collection of com

docs.unity3d.com

https://www.reddit.com/r/Unity3D/comments/hk4r5u/new_input_system_player_input_component_and_send/

 

From the Unity3D community on Reddit

Explore this post and more from the Unity3D community

www.reddit.com

 

+ Recent posts