Unity

유니티 움직임 구현 - 플레이어 이동 및 점프, 1인칭 시점

Lavin 2024. 1. 25. 11:06
반응형

안녕하세요

오늘은 유니티 1인칭 시점 플레이어 이동 및 점프를 구현해봤습니다.


[하이어라키]

  • PlayerModel은 캡슐 오브젝트를 사용했습니다
  • CameraPos는 PlayerModel의 머리 부분에 위치했습니다 Position (0, 0.74, 0)
  • Orientation은 Position (0, 0 ,0) 입니다.
  • CameraHolder는 Position (0, 1.5, 0) 입니다.

[MoveCamera.cs]

#region 변수
[SerializeField] private Transform cameraPosition;
#endregion // 변수

#region 함수
/** 초기화 => 상태를 갱신한다 */
private void Update()
{
    transform.position = cameraPosition.position;
}
#endregion // 함수
  • cameraPosition 변수에 MainCamera를 넣어줍니다.
  • MoveCamera.cs는 CameraHolder에 넣어줍니다.

[PlayerCamera.cs]

#region 변수
[Header("=====> 감도 설정 <=====")]
[SerializeField] private float mouseSensitivityX;
[SerializeField] private float mouseSensitivityY;

[Header("=====> 방향 <=====")]
public Transform orientation;

private float xRotation;
private float yRotation;
#endregion // 변수

#region 함수
/** 초기화 => 상태를 갱신한다 */
private void Update()
{
    // 마우스 수평/수직
    float mouseX = Input.GetAxisRaw("Mouse X") * mouseSensitivityX;
    float mouseY = Input.GetAxisRaw("Mouse Y") * mouseSensitivityY;

    // 마우스가 위로 올라갈 때 X가 바뀜
    yRotation += mouseX;
    xRotation -= mouseY;

    // 수직회전 고정
    xRotation = Mathf.Clamp(xRotation, -90f, 90f);

    // 회전 적용
    transform.rotation = Quaternion.Euler(xRotation, yRotation, 0);
    orientation.rotation = Quaternion.Euler(0, yRotation, 0);
}
#endregion // 함수
  • mouseSensitivity는 직접 테스트해보면서 조절하시면 됩니다.
  • orientation은 Player객체 하위에 있는 Orientation 객체를 넣어주면 됩니다.
  • PlayerCamera.cs는 MainCamera에 넣어줍니다.

[PlayerMovemenet.cs]

#region 변수
[Header("=====> 이동 <=====")]
[SerializeField] private float moveSpeed;
[SerializeField] private float correctMoveSpeed;
[SerializeField] private float baseDrag;
[SerializeField] private Transform orientation; 

[Header("=====> 점프 설정 <=====")]
[SerializeField] private float jumpPower;
[SerializeField] private float jumpCooldown;
[SerializeField] private float playerHeight;
[SerializeField] private float correctPlayerHeight;
[SerializeField] private LayerMask groundLayer;

[Header("=====> 키 입력 <=====")]
[SerializeField] private KeyCode jumpKey = KeyCode.Space;

[Header("=====> 인스펙터 값 확인 <=====")]
[SerializeField] private float airMultiplier;

private bool isJump;
private bool isGround;

private float horizontalInput;
private float verticalInput;

private Vector3 moveDirection;

private Rigidbody rigid;
#endregion // 변수

#region 함수
/** 초기화 */
private void Awake()
{
    rigid = GetComponent<Rigidbody>();
    rigid.freezeRotation = true;

    // 점프 초기화
    PlayerResetJump();
}

/** 초기화 => 상태를 갱신한다 */
private void Update()
{
    // 오브젝트의 높이 절반 + 보정값
    isGround = Physics.Raycast(transform.position, Vector3.down, playerHeight * 0.5f + correctPlayerHeight, groundLayer);

    // 플레이어 입력처리
    PlayerInput();
    // 플레이어 속도제어
    PlayerSpeedControl();
    // 저항 값 제어
    DragAirControl();
}

/** 초기화 => 상태를 갱신한다 */
private void FixedUpdate()
{
    // 플레이어 이동
    PlayerMove();
}

/** 입력처리 */
private void PlayerInput()
{
    // 움직임
    horizontalInput = Input.GetAxisRaw("Horizontal");
    verticalInput = Input.GetAxisRaw("Vertical");
    
    // 점프
    if(Input.GetKey(jumpKey) && isJump && isGround)
    {
        isJump = false;

        // 점프
        PlayerJump();

        // 점프 쿨타임
        Invoke(nameof(PlayerResetJump), jumpCooldown);
    }
}

/** 플레이어 이동 */
private void PlayerMove()
{
    // 이동방향 계산
    moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput;

    // 이동
    rigid.AddForce(moveDirection.normalized * moveSpeed * correctMoveSpeed * airMultiplier, ForceMode.Force);
}

/** 플레이어 속도제어 */
private void PlayerSpeedControl()
{
    // 속도
    Vector3 currentVelocity = new Vector3(rigid.velocity.x, 0f, rigid.velocity.z);

    // 현재 속도가 이동속도보다 클 경우
    if(currentVelocity.magnitude > moveSpeed)
    {
        // 같은 방향 moveSpeed로 크기 제한
        Vector3 limitVelocity = currentVelocity.normalized * moveSpeed;
        rigid.velocity = new Vector3(limitVelocity.x, rigid.velocity.y, limitVelocity.z);
    }
}

/** 플레이어 점프 */
private void PlayerJump()
{
    rigid.velocity = new Vector3(rigid.velocity.x, 0f, rigid.velocity.z);

    rigid.AddForce(transform.up * jumpPower, ForceMode.Impulse);
}

/** 점프 초기화 */
private void PlayerResetJump()
{
    isJump = true;
}

/** 저항 값 제어 */
private void DragAirControl()
{
    // 공기저항
    rigid.drag = isGround ? baseDrag : 1;

    // 점프했을때 안했을때 움직이는 속도 조정
    airMultiplier = isGround ? 1 : (1 / (baseDrag + 1));
}
#endregion  // 함수
  • playerHeight는 오브젝의 높이를 구하여 설정해주시면 됩니다. 캡슐 오브젝트의 높이는 2 입니다.
  • correct 변수는 보정값입니다.
  • PlayerMovement.cs는 Player에 넣어줍니다.

[인스펙터]

 

[추가 설정]

  • Layer에 Ground를 추가하시고 바닥이 되는 객체의 Layer를 Ground로 바꿔 주시면 됩니다.
반응형