더보기
목차
- Move() 역할
- Move() 변수 설명
- Move() 함수 코드 분석
1. Move() 역할
Move() 함수는 Update()에서 호출되며, Player의 이동 관련 함수이다.
2. Move() 변수 설명
- Move Speed : Player의 기본 이동 속도
- Sprint Speed : Player의 달리기(질주) 속도
- RotationSmoothTime : Player가 이동 방향을 향해 회전하는 속도 (0.0f ~ 0.3f)
- SpeedChangeRate : 가속/감속으로 '걷기>달리기' or '달리기>걷기'에서 부드러운 모션을 제공
3. Move() 함수 코드 분석
(1) 걷기/달리기 속도 설정
// 질주 상태에 따른 질주 속도/이동 속도 조절
float targetSpeed = _input.sprint ? SprintSpeed : MoveSpeed;
// 이동하고 있지 않은 경우, 목표 속도는 0으로 설정함
if (_input.move == Vector2.zero) targetSpeed = 0.0f;
- _input.sprint : StartAssetsInputs에서 달리기(질주) 상태 여부를 check하며 bool 타입이다.
달리는 중이면 true, 걷는 중이면 false를 반환한다. - _input.sprint에 따라 targetSpeed를 설정한다. 달리는 중이면 SprintSpeed, 걷는 중이면 MoveSpeed이다.
- _input.move : StartAssetsInputs에서 이동 상태 여부를 check하며 Vector2 타입이다.
멈춰있으면 Vector2.zero, 이동 중이면 Vector2.zero가 아닌 값을 반환한다. - 멈춘 상태라면 targetSpeed를 0으로 설정한다.
(2) 가속/감속
// Player의 현재 수평 속도
float currentHorizontalSpeed = new Vector3(_controller.velocity.x, 0.0f, _controller.velocity.z).magnitude;
float speedOffset = 0.1f;
float inputMagnitude = _input.analogMovement ? _input.move.magnitude : 1f;
// 목표 속도 가속/감속
if (currentHorizontalSpeed < targetSpeed - speedOffset ||
currentHorizontalSpeed > targetSpeed + speedOffset)
{
// 이동이 자연스럽도록 설계된 가속/감속
_speed = Mathf.Lerp(currentHorizontalSpeed, targetSpeed * inputMagnitude,
Time.deltaTime * SpeedChangeRate);
// 속도를 소수점 이하 3자리까지 반올림
_speed = Mathf.Round(_speed * 1000f) / 1000f;
}
// 속도 변화가 없는 경우 : 목표 속도 유지
else
{
_speed = targetSpeed;
}
_animationBlend = Mathf.Lerp(_animationBlend, targetSpeed, Time.deltaTime * SpeedChangeRate);
if (_animationBlend < 0.01f) _animationBlend = 0f;
- Player의 속도 변화가 있다면, 이동이 자연스럽도록 가속/감속을 준다.
- Player의 속도 변화가 없다면 목표 속도를 유지한다.
- Mathf.Lerp : 선형 보간(a: 일차 함수 시작 값/b: 일차 함수 종료 값/t: 얻고 싶은 값의 위치[비율])
(ex: a=(0,0), b=(100,100), t=0.5라면 (50,50)을 반환한다.) - t는 고정으로 설정되어 있으므로 속도 고정을 따로 설정할 필요가 없다.
(3) 회전(입력 방향)
// 입력 방향 정규화
Vector3 inputDirection = new Vector3(_input.move.x, 0.0f, _input.move.y).normalized;
// 이동 중인 경우, 회전
if (_input.move != Vector2.zero)
{
_targetRotation = Mathf.Atan2(inputDirection.x, inputDirection.z) * Mathf.Rad2Deg +
_mainCamera.transform.eulerAngles.y;
float rotation = Mathf.SmoothDampAngle(transform.eulerAngles.y, _targetRotation, ref _rotationVelocity,
RotationSmoothTime);
// 카메라 회전 : 입력방향을 향하도록 회전
transform.rotation = Quaternion.Euler(0.0f, rotation, 0.0f);
}
Vector3 targetDirection = Quaternion.Euler(0.0f, _targetRotation, 0.0f) * Vector3.forward;
- Player가 이동중인 경우, 카메라 회전 시킴
- Mathf.Atan2 : 탄젠트를 적용하여 각도(Radian) 반환
- Mathf.Rad2Deg : Radian 값을 Degree로 변환
- Mathf.SmoothDampAngle : 부드러운 각도 변화
- Quaternion.Euler : Euler 각을 Quaternion(방향/회전 둘 다 표현)으로 변환
(Euler는 x → y → z 순으로 계산되어 축이 겹치는 현상[짐벌락]이 발생할 수 있음)
(4) Player 이동 및 애니메이션 적용
// Player 이동
_controller.Move(targetDirection.normalized * (_speed * Time.deltaTime) +
new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
// 애니메이션 적용
if (_hasAnimator)
{
_animator.SetFloat(_animIDSpeed, _animationBlend);
_animator.SetFloat(_animIDMotionSpeed, inputMagnitude);
}
(5) 전체 코드
private void Move()
{
// set target speed based on move speed, sprint speed and if sprint is pressed
// 질주 상태에 따른 질주 속도/이동 속도 조절
float targetSpeed = _input.sprint ? SprintSpeed : MoveSpeed;
// a simplistic acceleration and deceleration designed to be easy to remove, replace, or iterate upon
// 제거/교체/반복이 자연스럽도록 설계된 가속/감속
// note: Vector2's == operator uses approximation so is not floating point error prone, and is cheaper than magnitude
// 참고 : Vector2의 == 연산자는 근사치를 사용하므로 부동 소수점 오류가 발생하지 않음
// if there is no input, set the target speed to 0
// 이동하고 있지 않은 경우, 목표 속도는 0으로 설정함
if (_input.move == Vector2.zero) targetSpeed = 0.0f;
// a reference to the players current horizontal velocity
// Player의 현재 수평 속도
float currentHorizontalSpeed = new Vector3(_controller.velocity.x, 0.0f, _controller.velocity.z).magnitude;
float speedOffset = 0.1f;
float inputMagnitude = _input.analogMovement ? _input.move.magnitude : 1f;
// accelerate or decelerate to target speed
// 목표 속도 가속/감속
if (currentHorizontalSpeed < targetSpeed - speedOffset ||
currentHorizontalSpeed > targetSpeed + speedOffset)
{
// creates curved result rather than a linear one giving a more organic speed change
// 이동이 자연스럽도록 설계된 가속/감속
// note T in Lerp is clamped, so we don't need to clamp our speed
// Mathf.Lerp : 선형 보간(a: 일차 함수 시작 값/b: 일차 함수 종료 값/t: 얻고 싶은 값의 위치[비율])
// t는 고정으로 설정되어 있으므로 속도 고정 필요 X
_speed = Mathf.Lerp(currentHorizontalSpeed, targetSpeed * inputMagnitude,
Time.deltaTime * SpeedChangeRate);
// round speed to 3 decimal places
// 속도를 소수점 이하 3자리까지 반올림
_speed = Mathf.Round(_speed * 1000f) / 1000f;
}
// 속도 변화가 없는 경우 : 목표 속도 유지
else
{
_speed = targetSpeed;
}
_animationBlend = Mathf.Lerp(_animationBlend, targetSpeed, Time.deltaTime * SpeedChangeRate);
if (_animationBlend < 0.01f) _animationBlend = 0f;
// normalise input direction
// 입력 방향 정규화
Vector3 inputDirection = new Vector3(_input.move.x, 0.0f, _input.move.y).normalized;
// note: Vector2's != operator uses approximation so is not floating point error prone, and is cheaper than magnitude
// 참고 : Vector2의 != 연산자는 근사치를 사용하므로 부동 소수점 오류가 발생하지 않음
// if there is a move input rotate player when the player is moving
// 이동 중인 경우, Player가 움직일 때 회전시킴
if (_input.move != Vector2.zero)
{
// Mathf.Atan2 : 탄젠트 적용 -> 각도(Radian) 반환
// Mathf.Rad2Deg : Radian -> Degree
// Mathf.SmoothDampAngle : 부드러운 각도 변화
_targetRotation = Mathf.Atan2(inputDirection.x, inputDirection.z) * Mathf.Rad2Deg +
_mainCamera.transform.eulerAngles.y;
float rotation = Mathf.SmoothDampAngle(transform.eulerAngles.y, _targetRotation, ref _rotationVelocity,
RotationSmoothTime);
// rotate to face input direction relative to camera position
// 카메라 회전 : 입력방향을 향하도록 회전
transform.rotation = Quaternion.Euler(0.0f, rotation, 0.0f);
}
Vector3 targetDirection = Quaternion.Euler(0.0f, _targetRotation, 0.0f) * Vector3.forward;
// move the player
_controller.Move(targetDirection.normalized * (_speed * Time.deltaTime) +
new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
// update animator if using character
if (_hasAnimator)
{
_animator.SetFloat(_animIDSpeed, _animationBlend);
_animator.SetFloat(_animIDMotionSpeed, inputMagnitude);
}
}
사담
순서대로 차례차례 올리려고 노력 중이지만, 이미 개발 후에 글을 작성하려니 순서가 뒤죽박죽이 되고 말았다😅
Move() 함수 분석 다음 글은 Grounded()와 JumpAndGravity()를 작성해 볼 예정이다!