3 분 소요

Intro

이번 포스팅에서는 예전에 만들었다 삭제한 콤보공격을 구현해보았습니다.

이번에는 코루틴을 사용하기보다는 애니메이션 이벤트로 처리해보려고 노력했습니다.

현재 공격이 진행되는 순서입니다.

image

  • 공격키(C) 입력을 통해 PlayerController 클래스의 Attack() 함수가 호출됩니다.
    • PlayerController.Attack() 함수는 단순히 “Attack” 트리거를 발동시켜 공격 애니메이션을 실행하도록 합니다.
  • 실행되는 애니메이션은 애니메이션 이벤트를 통해 특정 타이밍에 PlayerController.TriggerAttack() 함수가 호출됩니다.
    • PlayerController.TriggerAttack() 함수는 Weapon 클래스의 Attack() 즉, Punch 클래스의 Attack() 를 호출하여 공격판정을 실행합니다.


다음으로, 애니메이션의 Transition 에대한 이해가 필요했습니다.

image

공격키 입력을 통해 Attack 트리거를 발동시키면, Attack 애니메이션이 실행됩니다.


image

플레이어가 장착하고있는 무기에따라 WeaponType 가 결정되고, 네가지 공격 애니메이션 중 하나가 실행되는것까지 되어있는 상태입니다.

여기에 ComboCount 파라미터를 만들어 Attack_LeftPunch => Attack_RightPunch 로의 Transition 을 위한 조건을 달아주어야합니다.

image

정리

먼저, 콤보공격에 필요한 정보들을 정리해보았습니다.

  1. ComboCount 설정
    • ComboCount 는 현재 공격이 몇번째 공격인지를 알기위한 정보입니다.
    • 이것에 대한 처리는 PlayerController 클래스에서 처리할 수도 있지만, 그것보다 콤보공격이 가능한 무기만이 필요한 처리이므로 무기클래스(ex. Punch) 에서 처리하도록 하였습니다.
  2. 콤보공격이 가능한 타이밍
    • 콤보공격을 수행할 수 있는 상태인지를 체크하기위한 플래그변수 isComboAllowed 가 필요하였습니다.
    • 이것은 공격애니메이션 도중에 True 가 되었다가, 공격애니메이션이 끝날때에는 다시 False가 되어야합니다.
  3. 콤보공격을 위한 함수
    • PlayerController 클래스에서 ComboAttack() 함수를 만들어 처리하도록 했습니다.
    • ComboAttack() 함수는 Attack() 함수와 마찬가지로, 단순히 애니메이션 실행을 위한 트리거만 발동시키지만, 콤보공격만을 위한 조건을 통해 수행됩니다.


즉,

애니메이션과 애니메이션 이벤트의 처리는 PlayerController 클래스에서 수행하고,

애니메이터 파라미터(ComboCount)의 처리는 Punch 클래스에서 수행하도록 하였습니다.

Animation Transition

Animation Transition 에서, 다음 항목에 대한 이해가 필요했습니다.

image


Exit Time 항목은

(A) 애니메이션에서 (B) 애니메이션이 연결될 때, (A) 애니메이션이 얼마만큼 실행되었을 때 (B) 애니메이션으로 넘어갈지에 대한 설정입니다.

Exit Time 는 0 ~ 1 의 값을 가지며

0 에 가까울수록 (A) 애니메이션은 짧게 실행되고, 1에 가까울수록 (A) 애니메이션이 끝까지 실행된 후 (B) 애니메이션이 실행됩니다.


또한 Transition Duration(s) 항목은

(A) 애니메이션에서 (B) 애니메이션이 연결될 때 자연스러운 연출을 위한 항목(블렌딩)으로,

적절히 설정한다면 (A) 애니메이션과 (B) 애니메이션이 원래 하나의 애니메이션인것처럼 연출할 수 있습니다.


이에 관해서

두 애니메이션에 애니메이션 이벤트들이 존재할 때 어떤 방식으로 진행되는지 테스트해봤습니다.

  • (A) 애니메이션과 (B) 애니메이션의 시작과 끝에는 ‘A’, ‘B’, ‘C’, ‘D’ 라는 애니메이션 이벤트가 설정되어있다고 가정하였습니다.


두 애니메이션의 자연스러운 전환을 위하여 아래와 같이 설정되어있을 때

image

처음에는 블렌딩 여부와 관계없이 A -> B -> C -> D 순의 이벤트가 진행될것이라고 생각했습니다.

image

하지만 실제론 A -> C -> B -> D 순의 이벤트가 진행되었습니다.


따라서 뒤에있을 콤보어택 구현에서 애니메이션 이벤트를 활용할 때 주의하여 진행하여야합니다.


Punch 클래스

Punch 클래스는 기본공격을 위한 클래스로, 콤보공격이 가능합니다.

// Punch.cs
    private int maxComboCount = 1;

    // 공격 판정
    public override void Attack()
    {
        SetComboCount();

        attackOrigin = GameManager.Instance.player.transform.position + GameManager.Instance.player.transform.up;
        attackDir = GameManager.Instance.player.transform.forward;
        

        RaycastHit[] hits = Physics.BoxCastAll(
            attackOrigin,                       // 중심위치 : 플레이어
            boxSize,                            // 박스크기
            attackDir,                          // 공격방향     
            Quaternion.identity,                // 회전X
            attackRange,                        // 공격최대거리
            LayerMask.GetMask("Monster")
            );
        
        // 한마리만 공격
        if(hits.Length > 0)
        {
            Monster monster = hits[0].collider.GetComponent<Monster>();
            if (monster != null)
            {
                monster.GetDamaged(DataManager.Instance.GetPlayerData().Damage);
            }
        }
    }

    // ComboCount 설정
    private void SetComboCount()
    {
        if (GameManager.Instance.player.CurComboCount < maxComboCount)
            GameManager.Instance.player.CurComboCount++;
        else
            GameManager.Instance.player.CurComboCount = 0;
    }
  • 기본공격은 왼손 -> 오른손 의 콤보공격이 있습니다.
    • 따라서 maxComboCount = 1
  • SetComboCount() : 최대 콤보공격(maxComboCount) 보다 작을때에는 ComboCount 파라미터값을 증가, 최대에 도달했을때는 0으로 설정합니다.

  • SetComboCount() 함수가 호출되는 타이밍은 공격판정이 수행되는 타이밍인 Attack() 함수에서 실행됩니다.

PlayerController 클래스

PlayerController 클래스에서 추가되는 부분입니다.

// PlayerController.cs

    readonly private int hashComboCount = Animator.StringToHash("ComboCount");
    private bool isComboAllowed = false;        // 콤보가능여부

    public int CurComboCount
    {
        get => anim.GetInteger(hashComboCount);
        set => anim.SetInteger(hashComboCount, value);
    }

    private void Update()
    {
        ComboAttack();
    }

    // 플레이어 콤보 공격
    private void ComboAttack()
    {
        if(isAttackKeyDown && isAttacking && isComboAllowed)
        {
            anim.SetTrigger(hashAttackTrigger);
        }
    }

    #region ** Animation Events **
    private void SetIsAttackingTrue() => isAttacking = true;

    private void SetIsAttackingFalse() => isAttacking = false;

    private void SetIsComboAllowedTrue() => isComboAllowed = true;

    private void SetIsComboAllowedFalse() => isComboAllowed = false;

    private void ResetComboCount() => CurComboCount = 0;
    #endregion
  • isComboAllowed : Combo 공격이 가능한지의 여부를 판별할 변수

  • ComboAttack() : 공격키 입력 & 공격중인상태 & 콤보공격이 가능한상태 일때 호출

  • 기존의 애니메이션 이벤트 함수중 반전을 이용한 방식(ex. isAttacking = !isAttacking)를 없애고, 두가지 함수로 쪼개어 작성하였습니다.

테스트

image

댓글남기기