
오늘은 시점을 3인칭으로 변경해보기로 했다.
진짜 금방 할 수 있을줄 알았는데 하루를 다 태웠다 ㅎㅎ
3인칭으로 변경함에 따라 문제가 줄줄이 발생했고,
그걸 수정하는게 좀 시간을 많이 잡아먹었다.
우선 3인칭으로 변경함에 따라 플레이어 모델이 필요했다.
그래서 에셋 스토어에서 무료 에셋을 받아서 사용했다.

귀여운 녀석으로 적용하였다.
애니메이션도 같이 있어서 그걸 사용하였다.
기존 1인칭 시점은 플레이어의 자식으로 카메라를 두었는데,
3인칭으로 변경하면서 밖으로 빼주고 뒤로 배치시켰다.


그 후 PlayerController 스크립트를 수정해주었다.
private void LateUpdate()
{
CameraRotate();
}
---------------------------------------------------------------------------
void CameraRotate()
{
camYaw += lookInput.x * cameraSensitivity;
camPitch -= lookInput.y * cameraSensitivity;
camPitch = Mathf.Clamp(camPitch, -8.6f, 60f);
Quaternion rotation = Quaternion.Euler(camPitch, camYaw, 0);
Vector3 offset = new Vector3(0, cameraHeight, -cameraDistance);
cameraTransform.position = transform.position + rotation * offset;
cameraTransform.LookAt(transform.position + Vector3.up * 1.5f);
}
기존에는 localEulerAngles를 변경해서 시점을 움직이는 방식이였는데,
LookAt을 사용하여 카메라가 플레이어를 바라보도록 설정해주었고
Mathf.Clamp를 사용하여 y축 회전의 제한을 두었다. (min, max 이런식으로 변경해야겠다.)
LateUpdate를 통해 플레이어를 자연스럽게 따라오도록 하였다.
offset은 혹시라도 마우스 휠로 줌 인,아웃 되는 걸 해볼까 해서 우선 넣어뒀는데
그걸 할 수 있을지는 잘 모르겠다. 내일 시간 남으면 할 것 같다.
발생한 문제
카메라도 잘 따라오고 회전도 잘되는데, 플레이어의 회전이 고정되었고
움직임도 이상했다. 그래서 움직임 관련 메서드를 수정하였다.
기존 움직임도 1인칭을 기준으로 작성한 것이기 때문에 문제가 발생한 것 같다.
그래서 3인칭에 맞게 움직임이 카메라 방향 기준으로 움직이게 변경해주었다.
Vector3 cameraForward = Camera.main.transform.forward;
cameraForward.y = 0;
Vector3 cameraRight = Camera.main.transform.right;
cameraRight.y = 0;
// 입력값으로 이동 방향 계산
Vector3 moveDirection = (cameraForward * moveInput.y + cameraRight * moveInput.x).normalized;
// 이동하는 방향을 바라보도록 회전
if (moveDirection != Vector3.zero)
{
transform.forward = Vector3.Slerp(transform.forward, moveDirection, Time.deltaTime * 10f);
}
// 걷기, 달리기 설정
float speed = isRun ? runSpeed : moveSpeed;
Vector3 velocity = moveDirection * speed;
velocity.y = _rigidbody.velocity.y;
_rigidbody.velocity = velocity;
원래 transform.forward와 transform.right를 사용했는데
그걸 카메라의 위치로 바꿔주었다.
normalized를 쓴 이유는 대각선 방향 때문에 사용하였다.
플레이어가 회전하지 않는 부분은 항상 이동방향을 바라보는 방향으로 해서 해결하였다.
기존 코드에서는 걷기와 달리기에 대한 부분이 꽤 길었는데
삼항 연산자를 이용하여 좀 더 간결하게 수정해보았다.

발생한 문제
움직임이 잘되어서 기분이 매우 좋았었는데, 점프가 안되는 문제가 발생했다.
아마 모델을 추가하면서 그에 맞게 콜라이더를 수정을 하였는데
IsGrounded 메서드에서 땅인지 점프 중인지 구분해주었는데, ray의 설정이 문제인지
제대로 동작하지 않는 것 같았다.
bool IsGrounded()
{
float checkRadius = 1f;
bool groundCheck = Physics.CheckSphere(transform.position, checkRadius, groundLayerMask);
return groundCheck && _rigidbody.velocity.y <= 0f;
}
CheckSphere라는 걸 사용해보았다.
기존 방식과 동일한데 그냥 쉽게 이해하면 선이 구가 되었다고 생각하면 된다.
Physics.CheckSphere(Vector3 위치, float 반지름, LayerMask 레이어마스크)
해당 위치에 설정한 반지름의 구가 생성되서 레이어마스크가 충돌하면 true를 반환해준다.
더블 점프가 되는 문제도 있었는데
_rigidbody.velocity.y <= 0f 를 통해 속도가 0보다 같거나 작을때만
true를 반환해주어서 중복 되지 않게 해주었다.

기존 1인칭에서는 스크린의 가운데를 기준으로 raycast를 통해 상호작용을 했는데
3인칭으로 변경하니 해당 방식을 사용하기는 적합하지 않다고 생각이 들어서
OnTrigger 방식으로 수정했다.
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Interactable"))
{
curInteractable = other.GetComponent<IInteractable>();
if (curInteractable != null)
{
SetPromptText();
}
}
}
private void OnTriggerExit(Collider other)
{
if (curInteractable != null)
{
curInteractable = null;
promptText.gameObject.SetActive(false);
}
}
기존 방식은 update에서 raycast를 계속 해주었는데,
OnTrigger은 트리거 됐을 때만 동작하기 때문에 훨씬 좋았다.
그리고 많이 사용했던 방식이라 코드 작성하기 수월했다.

거의 수정하는데 하루를 다 써버렸다.
내일 4시까지 제출이기 때문에 마무리를 호다닥 해야겠다.
내일 할 것