Unity Package : [ Starter Assets ] Third Person Controller 사용
내가 구매한 Model 적용
내가 구현 할 게임은 3인칭 백 뷰 장르이다
WASD로 이동, 마우스를 고정시켜 마우스를 이용해 카메라를 회전하고
플레이어가 이동 시 카메라가 바라보는 방향에 따라 그 위치로 플레이어도 회전시키려고 한다
에셋 내에 ThirdPersonController.cs를 대폭 수정했다
StarterAssetsInput.cs는 SendMessage 형태로 코드가 구현 돼 있었는데 개인적으로 나는 Invoke Unity Event가 커스터마이징하는데 더 편해서 수정함
private Vector2 move;
{....}
public void OnMove(InputAction.CallbackContext context)
{
MoveInput(context.ReadValue<Vector2>());
}
{....}
// 실질적인 작업을 하는 함수들 ( Joy Stick 에서도 불려지는 애들이다. )
public void MoveInput(Vector2 newMoveDirection)
{
move = newMoveDirection;
}
{....}
// PlayerManager에서부터 변수로 바로 접근 하는 대신 이 함수로 접근
public Vector2 GetMove()
{
return move;
}
{....}
public void GroundedCheck()
{
Vector3 spherePosition = new Vector3(transform.position.x, transform.position.y - groundedOffset,
transform.position.z);
grounded = Physics.CheckSphere(spherePosition, groundedRadius, groundLayers,
QueryTriggerInteraction.Ignore);
animator.SetBool(_animIDGrounded, grounded);
}
public void ApplyGravity()
{
if (grounded)
{
_fallTimeoutDelta = fallTimeout;
animator.SetBool(_animIDFreeFall, false);
if (_verticalVelocity < 0.0f)
{
_verticalVelocity = -2f;
}
}
else
{
if (_fallTimeoutDelta >= 0.0f)
{
_fallTimeoutDelta -= Time.deltaTime;
}
else
{
animator.SetBool(_animIDFreeFall, true);
}
}
if (_verticalVelocity < _terminalVelocity)
{
_verticalVelocity += gravity * Time.deltaTime;
}
}
public void Move()
{
// Target Speed 결정
if(_input.GetMove() == Vector2.zero)
{
targetSpeed = 0.0f;
}
else if (!_input.IsSprinting())
{
targetSpeed = runSpeed;
}
else
{
targetSpeed = sprintSpeed;
}
if (targetSpeed > 0.0f)
{
// a reference to the players current horizontal velocity
currentHorizontalSpeed = new Vector3(characterController.velocity.x, 0.0f, characterController.velocity.z).magnitude;
speedOffset = 0.1f;
inputMagnitude = _input.IsAnalogue() ? _input.GetMove().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
speed = Mathf.Lerp(currentHorizontalSpeed, targetSpeed * inputMagnitude,
Time.deltaTime * speedChangeRate);
// round speed to 3 decimal places
speed = Mathf.Round(speed * 1000f) / 1000f;
}
else
{
speed = targetSpeed;
}
animationBlend = Mathf.Lerp(animationBlend, targetSpeed, Time.deltaTime * speedChangeRate);
if (animationBlend < 0.01f) animationBlend = 0f;
}
else
{
speed = 0;
//2배 빠르게 멈추기
animationBlend = Mathf.Lerp(animationBlend, targetSpeed, Time.deltaTime * speedChangeRate * 2);
if (animationBlend < 0.01f) animationBlend = 0f;
}
// normalise input direction
Vector3 inputDirection = new Vector3(_input.GetMove().x, 0.0f, _input.GetMove().y).normalized;
if (_input.GetMove() != Vector2.zero)
{
// Rotation
targetRotation = Mathf.Atan2(inputDirection.x, inputDirection.z) * Mathf.Rad2Deg +
mainCamera.transform.eulerAngles.y;
float rotation = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetRotation, ref rotationVelocity,
rotationSmoothTime);
if (!playerManager.LockActivate)
{
transform.rotation = Quaternion.Euler(0.0f, rotation, 0.0f);
}
// 나중에 락 온 기능 생성 시 활성화
//else
//{
// transform.rotation = Quaternion.Euler(0.0f, transform.eulerAngles.y, 0.0f);
//}
}
// Move ( rotation 기반으로 무브 )
Vector3 targetDirection = Quaternion.Euler(0.0f, targetRotation, 0.0f) * Vector3.forward;
characterController.Move(targetDirection.normalized * (speed * Time.deltaTime) +
new Vector3(0.0f, ggController.VerticalVelocity, 0.0f) * Time.deltaTime);
animator.SetFloat(_animIDSpeed, animationBlend);
animator.SetFloat(_animIDMotionSpeed, inputMagnitude);
}
input이 어떠냐에 따라 targetSpeed를 코드 시작부터 정의 시킴
본래 코드의 가독성이 너무 떨어져서 수정
움직임이 없으면 rotation 갱신하지 않기
안하면 멈춰있을때 플레이어가 자꾸 고정된 방향으로 회전함
그래서 input 입력이 없을때는 rotation 제한 걸어서 해결
LockActivate 기능 추가
현재 포스팅에는 쓰지 않을 예정인데 Lock On 기능 구현 시 필요한 부분
저 제약을 걸지 않으면 락 온 해도 Enemy 방향을 고정해서 바라보지않게 됨
현재 코드엔 보이지 않으나 최적화를 진행함
마지막 목차에서 설명하겠음
// Update is called once per frame
void Update()
{
//#region Gravity, Ground
gravityGroundController.GroundedCheck();
gravityGroundController.ApplyGravity();
//#endregion
if (canMove)
{
playerMovement.Move();
}
}
private void LateUpdate()
{
CameraRotation();
}
public void Move()
{
before = transform;
// 변화가 없을때는 Move 탈출
if(!System.Object.ReferenceEquals(before, null) && !System.Object.ReferenceEquals(after, null) &&
_input.GetMove() == Vector2.zero && before == after)
{
if (animationBlend == 0)
{
Debug.Log("NotMoving");
return;
}
}
// Target Speed 결정
if(_input.GetMove() == Vector2.zero)
{
...
}
{ .... }
after = transform;
에러 두개는 FootStep이라고 Audio Source를 지정안해줘서 일어나는 에러
움직이지 않을때 움직이고 다시 멈췄을때 Console에 Not Moving이 찍힘