
유니티 패키지 매니저를 통해 받아서 입력에 따른 조작을 시킬 수 있다.
project 창에서 Input Action을 만들면 아래와 같은 창이 나온다.


빈 창에 Action Properties를 만들고 필요에 따라 Value, Button과 타입을 지정한다.

프로퍼티를 설정하고 나면 키와 마우스에 따라 세부 입력한다.

프로퍼티 설정이 끝나면 이벤트를 실행시킬 메서드와 변수 메서드를 입력한다.

OnMove에서 InputAction의 이동 입력을 받고 Move가 거기에 속도 등을 더해 정제를 거친 후 최종적으로 FixedUpdate에서 물리 이동을 실행시킨다.
public class PlayerController : MonoBehaviour
{
[Header("Movement")]
public float moveSpeed;
public float runSpeed;
private Vector2 curMovementInput;
public float jumpPower;
public LayerMask groundLayerMask;
[Header("Look")]
public Transform camContainer;
public float minXLook;
public float maxXLook;
private float camCurXRot;
public float lookSensitivity;
private Vector2 mouseDelta;
private Rigidbody _rigidbody;
private void Awake()
{
_rigidbody = GetComponent<Rigidbody>();
}
private void Start()
{
Cursor.lockState = CursorLockMode.Locked; // 마우스 커서 잠금
}
private void FixedUpdate()
{
Move();
}
private void LateUpdate()
{
Look();
}
public void OnMove(InputAction.CallbackContext context) //InputAction 값을 받아옴
{
if (context.phase == InputActionPhase.Performed) //키를 누르고 있는 동안
{
curMovementInput = context.ReadValue<Vector2>(); //InputAction에서 설정한 Move는 Value, Vector2
}
else if (context.phase == InputActionPhase.Canceled) //키를 뗐을 때
{
curMovementInput = Vector2.zero;
}
}
private void Move()
{
Vector3 dir = transform.forward * curMovementInput.y + transform.right * curMovementInput.x;
dir *= moveSpeed;
dir.y = _rigidbody.velocity.y;
_rigidbody.velocity = dir;
//dir은 x,z축만 지정한 상황. 이걸 바로 velocity에 적용해버리면 y = 0이기 때문에
//점프를 하거나 떨어져도 언제나 dir.x, 0, dir.z로 유지됨.
//Rigidbory에 의한 중력 영향을 받게 하기 위해서 velocity.y를 넣어주는 것
}
public void OnJump(InputAction.CallbackContext context)
{
if(context.phase == InputActionPhase.Started && IsGrounded())
{
_rigidbody.AddForce(Vector2.up * jumpPower, ForceMode.Impulse);
Debug.Log("점프 입력");
}
}
public void OnLook(InputAction.CallbackContext context)
{
mouseDelta = context.ReadValue<Vector2>();
}
private void Look()
{
camCurXRot += mouseDelta.y * lookSensitivity; // 마우스 이동 변수(InputAction과 연결할)과 감도 변수를 저장
camCurXRot = Mathf.Clamp(camCurXRot, minXLook, maxXLook); //마우스 이동값 한계 설정
camContainer.localEulerAngles = new Vector3(-camCurXRot, 0, 0); //localEulerAngler: "축"으로 회전, - 넣어줘야 제대로 된 방향으로 회전함
transform.eulerAngles += new Vector3(0, mouseDelta.x * lookSensitivity, 0); //카메라 x축과 y축은 같은 오브젝트에서 처리하면 안됨
}
bool IsGrounded()
{
Ray[] ray = new Ray[4]
{
new Ray(transform.position + (transform.forward * 0.2f) + (transform.up * 0.01f), Vector3.down),
new Ray(transform.position + (-transform.forward * 0.2f) + (transform.up * 0.01f), Vector3.down),
new Ray(transform.position + (transform.right * 0.2f) + (transform.up * 0.01f), Vector3.down),
new Ray(transform.position + (-transform.right* 0.2f) + (transform.up * 0.01f), Vector3.down)
};
for(int i = 0; i < ray.Length; i++)
{
if (Physics.Raycast(ray[i], 0.1f, groundLayerMask)) return true;
}
return false;
}
}
private void Look()
{
camCurXRot += mouseDelta.y * lookSensitivity; // 마우스 이동 변수(InputAction과 연결할)과 감도 변수를 저장
camCurXRot = Mathf.Clamp(camCurXRot, minXLook, maxXLook); //마우스 이동값 한계 설정
camContainer.localEulerAngles = new Vector3(-camCurXRot, 0, 0); //마우스 이동과 x축 회전방향이 반대기 때문에 -로 넣어줌
transform.eulerAngles += new Vector3(0, mouseDelta.x * lookSensitivity, 0); //카메라 x축과 y축은 같은 오브젝트에서 처리하면 안됨
}
여기서 도대체 왜 mouseDelta 변수의 y를 받아놓고 그걸 x에 넣어주는 걸까?? mouseDelta.y를 mouseDelta.x로 바꿔보면 요상하게 빙빙 돌면서 자기 마음대로 회전한다.
이건 x 방향으로 이동하는 개념이 아니라
localEulerAngles를 통해서 x축을 기준으로 회전하는 것이기 때문이다.
y를 따라 이동하는 마우스의 값을 받아 camContainer.localEulerAngles의 "x축"에 넣으면 시점이 마우스와 같은 방향으로 회전하게 되는 것이다.
그래서 "벡터의 x 자리에 들어가는 건데 마우스 x값을 넣어줘야 되는 거 아닌가?"라는 생각으로 mouseDelta.x를 넣으면 x축 회전에 또 x값을 넣으니 이상하게 빙빙 돌았던 것이다.