InputSystem에서 받아온 값을 Move함수를 사용해 캐릭터 움직임 구현

2024. 10. 29. 16:00카테고리 없음

InputSystem에서 설정한 Action을 실행하는 로직

public void OnMove(InputAction.CallbackContext context) //입력값은 2차원벡터이다.
{
    if (context.phase == InputActionPhase.Performed) //InputActionPhase.Started : 키를누르는 순간만작동, Performed : 키가 눌린상태에서도 값을 받아옴
    {
        curMovementInput = context.ReadValue<Vector2>();
    }
    else if(context.phase == InputActionPhase.Canceled)
    {
        curMovementInput = Vector2.zero;
    }
}

위에서 저장한 변수값을 가지고 실제로 캐릭터 움직임을 구현하는 로직

void Move()
{
    //방향값 정해주고 거기에 속도를 곱해주
    //forward : 앞으로가고 뒤로가고 하는 것 (w, s 적용)
    Vector3 dir = transform.forward * curMovementInput.y + transform.right * curMovementInput.x;    //방향계산
    dir *= moveSpeed;       //속력 = Speed 빠르기 /속도 = 방향(velocity)이 있는 빠르기
    dir.y = _rigidbody.velocity.y;      //y축에 가하는 힘이없음/ 점프를 위해서 작성한 코드
    
    _rigidbody.velocity = dir;
}

구현한 움직임을 호출하는 로직

void FixedUpdate()  //물리연산을 할때에는 FixedUpdate에서 호출해주는게 좋다.
{
    Move();
}

 

위 코드를 작성하면서 들었던 의문들

1. _rigidbody.velocity에 정한 값을 저장해 주는데 velocity가 뭐지?

- 게임 오브젝트에 Rigidbody를 추가하면 그 오브젝트는 물리적인 속성을 비로서 가진다. 물리적인 속성을 가지게되면 물리를 관장하는 속성중에 속도(velocity)라는 필드가 있다. 

public class Rigidbody : Component
{
  /// <summary>
  ///   <para>The velocity vector of the rigidbody. It represents the rate of change of Rigidbody position.</para>
  /// </summary>
  public Vector3 velocity
  {
    get
    {
      Vector3 ret;
      this.get_velocity_Injected(out ret);
      return ret;
    }
    set => this.set_velocity_Injected(ref value);
  }

 

Vector3 타입으로 velocity 프로퍼티가 있어서 velocity를 사용할 수 있는거다.

그럼 이제부터 velocity가 뭔지 알아보자.

velocity를 알려면 Move함수 코드를 알아야 되는데

void Move()
{
    //방향값 정해주고 거기에 속도를 곱해주
    //forward : 앞으로가고 뒤로가고 하는 것 (w, s 적용)
    Vector3 dir = transform.forward * curMovementInput.y + transform.right * curMovementInput.x;    //방향계산
    dir *= moveSpeed;       //속력 = Speed 빠르기 /속도 = 방향(velocity)이 있는 빠르기
    dir.y = _rigidbody.velocity.y;      //y축에 가하는 힘이없음/ 점프를 위해서 작성한 코드
    
    _rigidbody.velocity = dir;
}

Vector3 dir = transform.forward * curMovementInput.y + transform.right * curMovementInput.x;

transform.forward는 z축방향에 크기가 1인 벡터(0, 0, 1)이고, transform.right는 x축방향에 크기가 1인 벡터(1, 0, 0)이다. 거기서 이제 InputSystem에서 받아온 값 y를 곱해주면 해당 벡터의 방향이 나온다.

예를 들면 w를 누르면 (0, 1)이 나온데 앞에 forward 먼저 계산하면 (0, 0, 1) 이 나오고  뒤에는 0이니깐 0이므로 dir값에 들어가는거는 (0, 0, 1)인 벡터가 들어가는 것이다. 이게 결국 하는일은 방향을 결정해주는거 뿐이다.

 

dir *= moveSpeed; :

속력과 속도의 차이를 알아야 하는 코드이다. 첫번째줄에서 방향을 계산했으면 두번째줄은 속력을 곱해주는 코드인것이다.

- 속력은 speed라고 하는데 방향이 없는 빠르기 라고 한다.

- 속도velocity라고 하고 방향이 있는 빠르기 라고 한다.

 

dir.y = _rigidbody.velocity.y; :

w, a, s, d로만 입력을 했을때에는 Unity에서 Y축에대가는 어떤 조합을해도 힘을 줄 수가 없다. 왜냐하면 첫번째 줄에서 transform.forward와 transform.right만을 사용하고 있고 transform.up은 사용하지 않아서 curMovementInput 에 어떠한 값이 들어온다고 해도 y축에다가는 어떠한 힘도 주지 못한다.

그럼 이 코드는 왜 적었냐?   점프때문이다.

점프를 구현하기 위해서 사용한거다. 밑에를 보면 점프기능중에 Vector2.up이라고 있는데 이게 y축 방향으로 힘을 가하는거여서 

OnMove를 이용해서 w, a, s, d로 평면상에서 이동을 하고 OnJump를 이용해서 점프한 값인 y값을 계속 받아오는거다.

public void OnJump(InputAction.CallbackContext context)
{
    if (context.phase == InputActionPhase.Started && isGrounded())
    {
        _rigidbody.AddForce(Vector2.up * jumpPower, ForceMode.Impulse);
    }
}

 

_rigidbody.velocity = dir; :

최종 값이 이제 게임 오브젝트에 붙어있는 Rigidbody의 속도를 업데이트 해준다. 그래서 움직일 수 있는거다.

 

2. FixedUpdate에서 굳이 Move()를 사용해야되나? 그냥 OnMove함수 호출 받았을때 Move()함수 바로 사용하면 안되나?

FixedUpdate(물리엔진)는 업데이트랑 다르게 내부적으로 50헤르츠로(0.02초) 항상 돌아간다.항상 돌아가게 할려고 유니티 엔진이 노력한다. 그래서 물체가 가만히 있더라고 유니티 엔진은 계속 돌아가야한다. 왜냐하면 언제 물체가 움직일지 모르니깐 물리세계를 유지하기위해서 계속 업데이트 해줘야한다. 그렇기때문에 어차피 돌아가는 거여서 여기에 넣어준거다.