using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR; using UnityEngine.XR.Interaction.Toolkit; public class ContinuousMovement : MonoBehaviour { public float gravity = -9.81f; //중력 상수 public float speed = 1f; public float additionalHeight = 0.2f; //눈~정수리 위까지의 추가 키 public XRNode inputSource; //인풋을 가져올 XRNode => Left Hand로 설정 public LayerMask groundLayer; //히트 체크할 땅의 레이어 private float fallingSpeed; //떨어지는 속도 private Vector2 inputAxis; //조이스틱 인풋값 private CharacterController character; //이동용 컴포넌트 private XRRig rig; //카메라 바라보는 방향 가져오기 위해 레퍼런스 가져옴 // Start is called before the first frame update void Start() { character = GetComponent(); rig = GetComponent(); } // Update is called once per frame void Update() { //XRNode로 device가져와서 인풋값 받기 InputDevice device = InputDevices.GetDeviceAtXRNode(inputSource); device.TryGetFeatureValue(CommonUsages.primary2DAxis, out inputAxis); } //CharacterController는 물리적으로 반응하며 움직이기 떄문에 FixedUpdate에서 처리해줘야 함 private void FixedUpdate() //0.02 * 50 = 1 { CapsuleFollowHeadset(); //※사원수를 쓰는 이유 : https://hoodymong.tistory.com/3 //카메라의 y 앵글값(=Yaw)을 사원수(Quaternion)으로 변환 Quaternion headYaw = Quaternion.Euler(0f, rig.cameraGameObject.transform.eulerAngles.y, 0f); //Quaternion x Vector3 하면 회전 Vector3 direction = headYaw * new Vector3(inputAxis.x, 0f, inputAxis.y); character.Move(direction * Time.fixedDeltaTime * speed); //중력 적용 : 발이 땅에 붙어있지 않을 때만 하강 속도가 증가하도록 bool isGrounded = CheckIfGrounded(); if (isGrounded) fallingSpeed = 0f; else fallingSpeed += gravity * Time.fixedDeltaTime; character.Move(Vector3.up * fallingSpeed * Time.fixedDeltaTime); } //발이 땅에 붙었는지?를 리턴하는 함수 private bool CheckIfGrounded() { Vector3 rayStart = transform.TransformPoint(character.center); //CharacterController의 중심점을 월드 스페이스 변환 float rayLength = character.center.y + 0.01f; //광선 길이는 CC의 키/2 보다 살짝만 더 길게해서 발 밑을 확실히 체크하도록 해줌 bool hasHit = Physics.SphereCast(rayStart, character.radius, Vector3.down, out RaycastHit hitInfo, rayLength, groundLayer); return hasHit; } //캐릭터 컨트롤러의 캡슐이 내 머리 위치 따라오도록 설정 void CapsuleFollowHeadset() { //카메라의 위치를 자기 자신 기준 local 좌표로 보정하여 저장 Vector3 capsuleCenter = transform.InverseTransformPoint(rig.cameraGameObject.transform.position); //Capsule의 높이를 rig의 높이 + 약간의 여유값에 맞춰줌 character.height = rig.cameraInRigSpaceHeight + additionalHeight; //수평(x, z) 좌표는 capsuleCenter를 따라가고, y는 character.height의 절반으로 해서 발을 땅에 붙이도록 해줌 character.center = new Vector3(capsuleCenter.x, character.height / 2f, capsuleCenter.z); } }