3 분 소요

이 글은 유튜브 Sebastian Graves Create Dark Souls를 보고 따라 만들면서 헷갈리는 부분을 정리한 글입니다.

구현 개요

이번엔 플레이어 행동 중 하나인 달리기를 구현한다.

달리기의 경우 구르기키와 동일한 키를 이용하여 사용하여
짧게 누를경우 구르기 길게 누를 경우 달리기가 되도록 해야한다.

초기 설정

  1. 애니메이션 추가
  2. 스크립트들 내용 추가

애니메이션 추가

이동 관련 애니메이션 블렌더 트리에 달리기를 추가해준다.

image

Script 추가된 내용

AnimatorHandler 에 추가된 내용


UpdateAnimatorValue 메소드에 매개변수 isSprinting을 추가해서 달리는 중이냐 아니냐에 따라 다른 애니메이션을 재생한다.


public void UpdateAnimatorValues(float verticalMovement, float horizontalMovement, 
bool isSprinting)
{
    ...

    if (isSprinting) // 달리는 중이면 애니메이션도 달리기로 바꿈
    {
        v = 2;
        h = horizontalMovement;
    }

    anim.SetFloat(vertical, v, 0.1f, Time.deltaTime);
    anim.SetFloat(horizontal, h, 0.1f, Time.deltaTime);
}


InputHandler 에 추가된 내용


b_Input의 값이 눌릴 때만이 아닌 누르고 있을 때 true값을 반환하도록 바꿈
그래서 inputActions.PlayerActions.Roll.IsPressed();가 사용됨

길게 누르면 달리기짧게 누르면 구르기 또는 백스텝이 되도록 함


public bool sprintFlag; // 달리기 중
public float rollInputTimer; // 얼마나 길게 눌렸는지를 알기위한 변수

private void HandleRollInput(float delta)
{
    //b_Input = inputActions.PlayerActions.Roll.phase == UnityEngine.InputSystem.InputActionPhase.Started;
    //b_Input = inputActions.PlayerActions.Roll.triggered;
    // 눌릴 때만 true
    b_Input = inputActions.PlayerActions.Roll.IsPressed();

    if (b_Input)
    {
        rollInputTimer += delta;
        sprintFlag = true;
    }
    else
    {
        if (rollInputTimer > 0 && rollInputTimer < 0.5f)
        {
            sprintFlag = false;
            rollFlag = true;
        }

        rollInputTimer = 0;
    }
}


PlayerLocomotion 에 추가된 내용


PlayerManager
public class PlayerLocomotion : MonoBehaviour
{
    Transform cameraObject;
    InputHandler inputHandler;
    Vector3 moveDirection;


    [HideInInspector]
    public Transform myTransform;
    [HideInInspector]
    public AnimatorHandler animatorHandler;

    public new Rigidbody rigidbody;
    public GameObject normalCamera;

    [Header("Status")]
    [SerializeField] float movementSpeed = 5;
    [SerializeField] float sprintSpeed = 7;
    [SerializeField] float rotationSpeed = 10;

    public bool isSprinting;

    void Start()
    {
        rigidbody = GetComponent<Rigidbody>();
        inputHandler = GetComponent<InputHandler>();
        animatorHandler = GetComponentInChildren<AnimatorHandler>();
        cameraObject = Camera.main.transform;
        myTransform = transform;
        animatorHandler.Initialized();

    }

    public void Update()
    {
        float delta = Time.deltaTime;

        isSprinting = inputHandler.b_Input;
        inputHandler.TickInput(delta);

        HandleMovement(delta);

        HandleRollingAndSprinting(delta);

    }


    #region Movement
    Vector3 normalVector;
    Vector3 targetPosition;

    private void HandleRotation(float delta)
    {
        Vector3 targetDir = Vector3.zero;
        float moveOverride = inputHandler.moveAmount;

        targetDir = cameraObject.forward * inputHandler.vertical;
        targetDir += cameraObject.right * inputHandler.horizontal;

        targetDir.Normalize();
        targetDir.y = 0;

        if (targetDir == Vector3.zero)
            targetDir = myTransform.forward;

        float rs = rotationSpeed;

        Quaternion tr = Quaternion.LookRotation(targetDir);
        Quaternion targetRotation = Quaternion.Slerp(myTransform.rotation, tr, rs * delta);

        myTransform.rotation = targetRotation;
    }
    public void HandleMovement(float delta)
    {
        // 구르기나 백스텝 도중 방향을 바꾸지 못하게 함
        if (inputHandler.rollFlag)
            return;

        moveDirection = cameraObject.forward * inputHandler.vertical;
        moveDirection += cameraObject.right * inputHandler.horizontal;
        moveDirection.Normalize();
        moveDirection.y = 0;

        float speed = movementSpeed;


        if (inputHandler.sprintFlag)
        {
            speed = sprintSpeed;
            isSprinting = true;
            moveDirection *= speed;
        }
        else
        {
            moveDirection *= speed;
        }

        Vector3 projectedVelocity = Vector3.ProjectOnPlane(moveDirection, normalVector);
        rigidbody.velocity = projectedVelocity;

        animatorHandler.UpdateAnimatorValues(inputHandler.moveAmount, 0, isSprinting);

        if (animatorHandler.canRotate)
        {
            HandleRotation(delta);
        }
    }

    public void HandleRollingAndSprinting(float delta)
    {
        // 한 번 실행하고 애니메이션이 끝날 때 까지 다시 실행 불가능
        if (animatorHandler.anim.GetBool("isInteracting"))
            return;

        if (inputHandler.rollFlag)
        {
            moveDirection = cameraObject.forward * inputHandler.vertical;
            moveDirection += cameraObject.right * inputHandler.horizontal;

            if (inputHandler.moveAmount > 0)
            {
                animatorHandler.PlayTargetAnimation("Rolling", true);
                moveDirection.y = 0;
                Quaternion rollRotation = Quaternion.LookRotation(moveDirection);
                myTransform.rotation = rollRotation;
            }
            else
            {
                animatorHandler.PlayTargetAnimation("BackStep", true);
            }
        }
    }

    #endregion
}


HandleMovemnet 함수


이 곳에 추가된 내용으로는 달리고 있을 떄와 걷고 있을 떄의 두가지 이동속도를 구현한다.

public void HandleMovement(float delta)
{
    
    if (inputHandler.rollFlag)
        return;

    moveDirection = cameraObject.forward * inputHandler.vertical;
    moveDirection += cameraObject.right * inputHandler.horizontal;
    moveDirection.Normalize();
    moveDirection.y = 0;

    float speed = movementSpeed;

//------------------------------------------------- 추가된 부분
// 달리기 입력값이 눌리고 있다면
    if (inputHandler.sprintFlag)
    {
        speed = sprintSpeed;
        isSprinting = true;
        moveDirection *= speed;
    }
    else
    {
        moveDirection *= speed;
    }
//------------------------------------------------- 

    Vector3 projectedVelocity = Vector3.ProjectOnPlane(moveDirection, normalVector);
    rigidbody.velocity = projectedVelocity;

//------------------------------------------------- 추가된 부분
// 3번째 인자값이 생김
    animatorHandler.UpdateAnimatorValues(inputHandler.moveAmount, 0, isSprinting);
//------------------------------------------------- 

    if (animatorHandler.canRotate)
    {
        HandleRotation(delta);
    }
}

Update에 추가된 내용


public void Update()
{
    float delta = Time.deltaTime;

    // isSprinting 변수를 갱신해줌
    isSprinting = inputHandler.b_Input;
    inputHandler.TickInput(delta);

    HandleMovement(delta);

    HandleRollingAndSprinting(delta);

}


PlayerManager에 추가된 내용

void Update()
{
    inputHandler.isInteracting = anim.GetBool("isInteracting");
    inputHandler.rollFlag = false;
    // sprintFlag를 계속 false로 갱신하여 누르고 있지 않으면 false로 만듬
    inputHandler.sprintFlag = false;
}

배운점

  1. 인풋 시스템의 IsPressed(); 라는 함수에 대해 알게되었다.

댓글남기기