One_KWS

게임 개발 일지 #2 - 플레이어 이동, 공격, 대시 본문

게임 개발

게임 개발 일지 #2 - 플레이어 이동, 공격, 대시

One-Kim 2023. 1. 7. 22:05

플레이어 행동 

현재 플레이어의 클래스 구조는 아래와 같다. 처음에는 스크립트 하나에 전부 구현했고 이후 여러번 코드를 다듬으면서 아래와 같은 구조가 되었다. 

 

이동, 공격, 대쉬에 대한 각각의 클래스는 IBehaviour 인터페이스를 구현하고 있다. IBehaviour 인터페이스는 해당 행동을 실행하는 Execute()와 다음 행동을 하기 전 현재 행동을 취소하기 위한 Cancel() 함수가 있다. IsOngoing은 현재 행동이 진행중인지 체크하기 위한 프로퍼티이다.

  public interface IBehaviour {
    public bool IsOngoing { get; }
    public void Execute();
    public void Cancel();
}

 

플레이어 애니메이션

플레이어의 Animator Controller는 아래와 같이 설정해주었다. 

Player Animator Controller

 

플레이어 이동

플레이어 이동시 InputManger로 부터 조이스틱의 값을 받는다. 현재 조이스틱이 가리키는 방향으로 플레이어의 방향을 바꿔주고 CharacterController의 Move 함수를 이용하여 플레이어가 바라보고 있는 방향으로 이동하도록 구현했다. 

public void Execute() {
    lotationVector.x = InputManager.Instance.MoveValue.x;
    lotationVector.z = InputManager.Instance.MoveValue.y;

    transform.localRotation = Quaternion.LookRotation(lotationVector);
    characterController.Move(transform.forward * (velocity * Time.deltaTime));

    animator.SetBool("move", true);
    isMoving = true;
}

 

Cancel 함수에서는 이동 애니메이션을 끄고 이동 상태를 false로 바꿔주었다. 

 public void Cancel() {
    animator.SetBool("move", false);
    isMoving = false;
}

플레이어 이동

 

플레이어 공격

콤보 공격으로 구현하기 위해 플레이어의 Animator Controller에서 attack_1 ~ 3에 해당하는 애니메이션을 넣어 주었고 다음 공격 애니메이션으로 넘어가게 하기 위해 bool 형식의 Parameter를 만들었다.

PlayerAnimatorController
다음 공격 애니메이션으로 넘기기 위한 Parameter

다음 콤보로 넘어갈 수 있도록 각각의 Transition의 Conditions을 아래와 같이 설정해주었다. 

공격 Parameter가 false 일 경우 다시 Idle 상태로 돌아갈 수 있도록 아래와 같이 설정해주었다.

플레이어 공격의 Execeute 함수는 아래와 같이 작성했다. 

[SerializeField] private float attackTime = 0.8f;

...

private bool isAttacking = false;
private WaitForSeconds waitForAttackTime;
private int currentCombo = 0;

...

 private void Awake() {
...
	 
    waitForAttackTime = new WaitForSeconds(attackTime);
    
...
}


public void Execute() {
    if (isAttacking) {
        return;
    }

    if (clickCount >= MAX_COMBO_COUNT) {
        return;
    }

    IsOngoing = true;
    currentCombo += 1;

    StartCoroutine(WaitUntilNextAttack());
    ShowAttackAnimation();
}

//공격 애니메이션이 끝나지 않았을 때 공격 버튼을 누를 경우 실행되지 않게 하기 위해 코루틴을 이용했다.
private IEnumerator WaitUntilAttackEnd() {
    isAttacking = true;
    yield return waitForAttackTime;
    isAttacking = false;
}

private void ShowAttackAnimation() {
    animator.SetBool($"attack_{currentCombo}", true);
}

 

Cancel 함수에서는 현재 콤보 카운트를 0으로 바꿔주고 attack_1 ~ 3의 애니메이션을 false로 바꿔주었다.

public void Cancel() {
    if (isAttacking) {
        return;
    }

    ResetComboCount();
    StartCoroutine(WaitUntilNextAttack());
    IsOngoing = false;
}

private void ResetComboCount() {
    currentCombo = 0;

    for (int i = 0; i < MAX_COMBO_COUNT; i++) {
        animator.SetBool($"attack_{i + 1}", false);
    }
}

 

위 코드만으로는 공격 후 다시 Idle 상태로 돌아가지 않아서 애니메이션이 끝나는 시점에 attack_1 ~ 3의 값을 false로 만들어 주기 위해 각 공격의 Animation에 Event를 넣어주었다.

 

해당 이벤트를 실행시켜 주기 위해 아래 코드를 추가했다.

public void OnEndAttack() {
    if (isAttacking) {
        return;
    }

    clickCount = 0;

    for (int i = 0; i < MAX_COMBO_COUNT; i++) {
        animator.SetBool($"attack_{i + 1}", false);
    }
}

 

플레이어 콤보 공격

플레이어 대쉬

몬스터의 공격을 피하거나 나중에 대쉬 + 공격 처럼 활용 하면 좋을 것 같아서 대쉬도 추가했다. 현재는 플레이어가 대쉬하는 기능만 개발된 상태이고 플레이어가 대쉬 중에는 몬스터의 공격이 맞지 않도록 하거나 공격 버튼과 연계되서 사용되도록 하는 부분은 추후 구현할 예정이다. (아마도 ..)

 

대쉬 이펙트가 플레이 되는 범위를 고려하여 플레이어 보다 뒤쪽에 놓았다. 이펙트는 에셋 스토어에서 사뒀던 것을 조금 수정했다. 

대쉬 이펙트

 

PlayerDash의 Execute에는 아래와 같이 구현했다. 대쉬 후 다음 대쉬까지 딜레이를 넣어 계속해서 대쉬가 되지 않게 했고 코루틴을 이용하여 일정 시간동안 isDashing이 true로 바꿔 FixedUpdate에서 isDashing이 true일 때 빠르게 앞으로 이동시키도록 구현했다. 

[SerializeField] private ParticleSystem dashEffect;
[SerializeField] private float dashDelay = 1f;

private float delayTime = 0;

public void Execute() {
    if (delayTime < dashDelay || isDashing) {
        return;
    }

    delayTime = 0;

    StartCoroutine(DashCoroutine());
    dashEffect.Play();
}

private IEnumerator DashCoroutine() {
    isDashing = true;
    animator.SetBool("evasion", true);

    yield return new WaitForSeconds(dashTime);

    isDashing = false;
    animator.SetBool("evasion", false);
}

private void FixedUpdate() {
    if (isDashing) {
        characterController.Move(transform.forward * (dashSpeed * Time.deltaTime));
        return;
    }

    delayTime += Time.deltaTime;
}

 

Cancel 함수에서는 대쉬 애니메이션과 대쉬 상태를 false로 바꿔주었다.

public void Cancel() {
    animator.SetBool("evasion", false);
    isDashing = false;
}

 

완성된 대쉬 기능. 만들고 보니 PlayerMovement 클래스에 구현해도 됐을 것 같다는 생각이 .. 

플레이어 대쉬