Quick Flow
| 단계 | 호출 기준 | 맡길 일 | 시간값 |
|---|---|---|---|
Update | 렌더 프레임마다, 간격 가변 | 입력 캡처, 게임 상태, UI | Time.deltaTime 또는 unscaledDeltaTime |
FixedUpdate | 물리 step마다, 한 프레임에 0회 이상 가능 | Rigidbody 힘·이동·물리 상태 | Time.fixedDeltaTime |
LateUpdate | 해당 프레임의 모든 Update 뒤 | 카메라 추적, 최종 위치 보정 | 보통 deltaTime |
단발 입력은 Update에서 요청으로 저장하고, FixedUpdate에서 한 번 소비합니다. 계속 누르는 이동 축은 최신 값을 저장해 매 물리 단계에 사용합니다.
private Vector2 _moveInput;
private bool _jumpRequested;
private void Update()
{
_moveInput = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
if (Input.GetButtonDown("Jump")) _jumpRequested = true;
}
private void FixedUpdate()
{
Vector3 step = new Vector3(_moveInput.x, 0f, _moveInput.y).normalized;
_rb.MovePosition(_rb.position + step * moveSpeed * Time.fixedDeltaTime);
if (!_jumpRequested) return;
_jumpRequested = false;
_rb.AddForce(Vector3.up * jumpImpulse, ForceMode.Impulse);
}호출 순서에서 달라지는 것
FixedUpdate는 다음 물리 시뮬레이션 직전에 호출됩니다. 렌더 프레임 속도와 물리 시간은 독립적이므로, 렌더 프레임 하나에 물리 step이 여러 번 실행되거나 실행되지 않을 수 있습니다. 따라서 FixedUpdate 안에서 프레임 수를 세거나 화면 UI를 매번 갱신하면 예상한 빈도가 되지 않습니다.
LateUpdate는 모든 스크립트의 Update가 끝난 뒤 실행됩니다. Transform으로 이동한 플레이어를 카메라가 바로 따라가게 할 때 적합합니다. 대상이 Rigidbody 물리 이동을 한다면 보간 설정과 카메라 시스템의 update mode까지 함께 확인합니다. LateUpdate라는 이름만으로 모든 카메라 흔들림이 해결되지는 않습니다.
입력은 무엇을 저장하는가
GetButtonDown처럼 짧게 참이 되는 edge 입력은 물리 step과 맞지 않을 수 있습니다. 위 예제처럼 bool을 한 번 소비하면, 한 렌더 프레임에서 FixedUpdate가 여러 번 호출돼도 점프는 한 번만 적용됩니다. 연속 축 값은 최신 값을 덮어쓰는 것으로 충분한 경우가 많습니다.
새 Input System을 쓰면 action callback에서 요청을 쌓고 FixedUpdate에서 소비하는 방식도 가능합니다. 다만 입력 버퍼에는 유효 시간이 필요할 수 있습니다. 예를 들어 착지 직전 점프를 허용하려면 요청 시각을 기록하고, 정한 입력 buffer 시간 안에서만 소비합니다. 무기한 bool은 나중에 의도하지 않은 점프로 남습니다.
private float _jumpRequestedAt = float.NegativeInfinity;
[SerializeField] private float jumpBufferSeconds = 0.12f;
private void Update()
{
if (Input.GetButtonDown("Jump")) _jumpRequestedAt = Time.time;
}
private void FixedUpdate()
{
if (!IsGrounded() || Time.time - _jumpRequestedAt > jumpBufferSeconds) return;
_jumpRequestedAt = float.NegativeInfinity;
_rb.AddForce(Vector3.up * jumpImpulse, ForceMode.Impulse);
}자주 틀리는 부분
| 증상 | 원인 | 수정 방향 |
|---|---|---|
| 점프가 가끔 빠지거나 두 번 적용됨 | edge 입력을 물리 단계에서 직접 읽거나 소비 표시가 없습니다. | Update/callback에서 저장하고 FixedUpdate에서 한 번 지웁니다. |
| 물리 이동이 프레임마다 달라 보임 | Rigidbody를 Update에서 바꾸거나 deltaTime을 섞었습니다. | Rigidbody 변경을 FixedUpdate와 fixedDeltaTime으로 모읍니다. |
| 카메라가 대상 뒤에서 튐 | 대상 위치가 확정되기 전에 카메라를 갱신합니다. | LateUpdate와 Rigidbody interpolation/update mode를 점검합니다. |
| 느린 프레임에서 처리 횟수가 폭증 | FixedUpdate를 프레임 1회라고 가정했습니다. | 물리 step 수와 Time.maximumDeltaTime 설정을 별도로 확인합니다. |
FixedUpdate에서 입력을 읽으면 안 된다는 말은 연속 입력까지 금지한다는 뜻이 아닙니다. 문제는 한 프레임만 유지되는 입력과 중복 소비입니다. 입력의 수명과 소비 횟수를 먼저 정한 뒤, 물리 변경만 고정 step에 맞춥니다.
참고 링크
3 sources