📌
3D 숙련 주차 강의 듣는 나: 이론 설명에 열심히 끄덕끄덕하면서 쉬운데? 하다가 스크립트 코드 짜는 거 보면서 멘탈 붕괴됨. 선생님. 진도가 너무 빨라요,, (߹-߹)
학습 내용
1. InputSystem(Behavior Invoke)
2. move 구현
3. Jump 구현
1. InputSystem(Behavior Invoke)
2D 게임에서 InputSystem 파트를 맡아서 이제 마스터 했다고 생각했는데 갑자기 튀어나온 Invoke. send Message는 액션을 함수로 전달해줘서 직접 그 함수를 스크립트에 작성해 써야했지만 Invoke는 Onclick 컴포넌트처럼 액션에 쓸 함수를 인스펙터에서 직접 할당해주는 형식이다.
그냥 send Message 쓰면 안 되나 싶어서 검색을 해봤는데.
- 성능이 중요하거나 컴파일 타임에 에러를 잡고 싶다면 Behavior.Invoke를 사용하는 것이 더 나은 선택입니다.
- 유연성과 다형성이 중요하거나 특정 상황에서만 메서드를 호출해야 한다면 SendMessage를 사용할 수 있지만, 일반적으로는 성능과 유지보수 측면에서 Behavior.Invoke가 더 좋습니다.
InputSystem에서 두 방법 모두 상황에 따라 유용할 수 있지만, 안정성과 성능이 중요한 대부분의 경우 Behavior.Invoke가 더 나은 선택입니다.
....... 우울하다. 이럴 거면 처음부터 Invoke로 쓸 걸.
✅ 어떻게 사용할까?
방법은 비슷하다. 각 액션에 할당할 함수를 모은 스크립트(플레이어 컨트롤러)를 만들고 나중에 플레이어 오브젝트에 붙여서 사용! 여기서 중요한 점 하나. InputValue를 매개변수로 받았던 SendMessage와 달리 Invoke는 InputAction.CallbackContext를 매개변수로 받아 콜백 시점을 정할 수 있다. 즉, 입력이 발생한 시점에 따라 메서드를 분리할 수 있다. 예를 들어, 버튼을 눌렀을 때, 떼었을 때, 또는 유지하고 있을 때 등 다양한 입력 상태를 구분한다는 것!
2. move 구현
public class PlayerController : MonoBehaviour
{
[Header("Movement")]
public float moveSpeed; // 속도
private Vector2 curMovementInput; //
public void OnMoveInput(InputAction.CallbackContext context)
{
if(context.phase == InputActionPhase.Performed) // 입력이 수행되면
{
curMovementInput = context.ReadValue<Vector2>(); // 이동 백터 값(x,y)을 읽음
}
else if(context.phase == InputActionPhase.Canceled) // 입력이 취소되면
{
curMovementInput = Vector2.zero; // (0,0)
}
}
private void Move()
{
Vector3 dir = transform.forward * curMovementInput.y + transform.right * curMovementInput.x;
// 이동 방향 결정
dir *= moveSpeed; // 속도 조절
dir.y = rigidbody.velocity.y; // y축 현재값 유지 (강제로 0으로 만들지 않음)
rigidbody.velocity = dir; // 이동 구현
}
정리하면 OnMoveInput 에서 이동 입력을 감지하면 이동 방향을 curMovementInput에 넣고, Move에서 curMovementInput에 따라 캐릭터가 물리 엔진을 사용해 실제로 이동하게 된다.
private void FixedUpdate()
{
Move();
}
매 프레임마다 호출되기 때문에 Update 메서드에 넣어주면 끝!
2. jump 구현
이전에 jump 구현을 해봤기 때문에 쉬울 거라고 생각했는데 move보다 더 큰 시련을 맞이했던 부분.
public float jumptForce; // 점프 높이 조절
public LayerMask groundLayerMask;
public void OnJumpInput(InputAction.CallbackContext context)
{
if(context.phase == InputActionPhase.Started && IsGrounded()) // 입력이 들어온 시점 && IsGround가 true
{
rigidbody.AddForce(Vector2.up * jumptForce, ForceMode.Impulse);
}
}
여기까진 쉬웠다. 물리 엔진으로 순간적인 힘을 줘서 점프포스 만큼 띄운다는 간단한 코드니까.
bool IsGrounded()
{
Ray[] rays = 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 < rays.Length; i++)
{
if (Physics.Raycast(rays[i], 0.1f, groundLayerMask))
{
return true;
}
}
return false;
}
여기서 무한 점프를 막기 위한 코드가 추가되면서 난이도가 높아졌다. 나는 땅에 닿았는지 체크하기 위해 colliderenter 메서드를 썼기 때문에 ray는 바로 이해하기가 어려웠다. 하나씩 분석해보자.
{
Ray[] rays = 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) // 좌
};
상하좌우 네 방향에서 아래 쪽으로 ray(가상의 선)을 발사한다. 현재 위치에서 약간 위쪽에서 쏘는 이유는 캐릭터의 발 바로 아래에서 시작하지 않도록 하기 위함이다.
for (int i = 0; i < rays.Length; i++)
{
if (Physics.Raycast(rays[i], 0.1f, groundLayerMask))
{
return true;
}
}
지면 충돌 여부를 검사한다. 0.1f 길이의 ray를 발사해서 그 거리 안에 지면이 있다면 isground는 true가 된다. 아니라면 false를 반환한다.
✅ 그런데 이 코드가 왜 플레이어 오브젝트의 collider 크기에 영향을 받을까?
이거 튜터님께 여쭤보려고 했는데 9시가 지나버렸다.
내일 여쭤보고 추가할 예정.
📝
TIL 좋은 점. 분명 이해가 안 돼서 정리한 거였는데 정리하다보니 이해됨. 짱!
'[내배캠] 본 캠프 개발 학습 > 매일매일 쓰는 TIL' 카테고리의 다른 글
10월 28일 월요일 본 캠프 개발 일지 | 개인 프로젝트 (1) (2) | 2024.10.28 |
---|---|
10월 25일 금요일 본 캠프 개발 일지 (6) | 2024.10.25 |
10월 23일 금요일 본 캠프 개발 일지 | 유니티 숙련 강의 (1) (4) | 2024.10.23 |
10월 22일 금요일 본 캠프 개발 일지 | NULL 참조 팀 프로젝트 (End) (2) | 2024.10.22 |
10월 18일 금요일 본 캠프 개발 일지 | NULL 참조 팀 프로젝트 (3) (8) | 2024.10.18 |