유니티 다크소울 따라만들기 ch_5 Sprint 달리기
이 글은 유튜브 Sebastian Graves Create Dark Souls를 보고 따라 만들면서 헷갈리는 부분을 정리한 글입니다.
구현 개요
이번엔 플레이어 행동 중 하나인 달리기를 구현한다.
달리기의 경우 구르기키와 동일한 키를 이용하여 사용하여
짧게 누를경우 구르기 길게 누를 경우 달리기가 되도록 해야한다.
초기 설정
- 애니메이션 추가
- 스크립트들 내용 추가
애니메이션 추가
이동 관련 애니메이션 블렌더 트리에 달리기를 추가해준다.
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;
}
배운점
- 인풋 시스템의 IsPressed(); 라는 함수에 대해 알게되었다.
댓글남기기