
이 글에는 인프런 파트너스 링크가 포함되어 있습니다. 이 링크를 통해 구매하시면 제가 수익을 받을 수 있어요. 🤗
들어가며
유니티를 처음 배우면서 가장 혼란스러웠던 것 중 하나가 바로 Update와 FixedUpdate의 차이였습니다. "둘 다 매 프레임 실행되는 거 아니야?"라고 생각했는데, 실제로 캐릭터 이동을 구현하다가 물리 연산이 이상하게 동작하는 걸 보고 나서야 제대로 공부하게 되었습니다.
이 글은 유니티를 시작한 지 얼마 안 된 분들, 특히 "Update에 다 넣으면 되는 거 아닌가?"라고 생각하시는 분들을 위한 글입니다.
게임 루프란?
기본 개념
게임은 영화와 비슷합니다. 영화가 초당 24프레임의 이미지를 빠르게 보여주듯, 게임도 매 프레임마다 화면을 갱신합니다. 이 과정을 반복하는 것이 게임 루프(Game Loop)입니다.
유니티에서는 이 게임 루프를 직접 작성할 필요가 없습니다. 엔진이 알아서 처리해주고, 우리는 특정 타이밍에 호출되는 함수들만 구현하면 됩니다.
유니티의 실행 순서
유니티는 매 프레임마다 정해진 순서로 함수를 호출합니다:
Awake() → OnEnable() → Start() → FixedUpdate() → Update() → LateUpdate()
여기서 핵심은 FixedUpdate, Update, LateUpdate 세 가지입니다.
Update() - 매 프레임 호출
특징
Update는 매 프레임마다 한 번 호출됩니다. 프레임 레이트에 따라 호출 간격이 달라집니다.
- 60fps → 초당 60번 호출
- 30fps → 초당 30번 호출
- 프레임 드랍 시 → 호출 간격 불규칙
언제 사용하나요?
- 키보드/마우스 입력 처리
- 애니메이션 트리거
- UI 갱신
- 물리와 무관한 이동 (Transform 직접 조작)
void Update()
{
// 입력 처리는 Update에서
if (Input.GetKeyDown(KeyCode.Space))
{
Jump();
}
// 비물리 이동
float horizontal = Input.GetAxis("Horizontal");
transform.Translate(Vector3.right * horizontal * speed * Time.deltaTime);
}
Time.deltaTime이 필요한 이유
여기서 Time.deltaTime을 곱하는 게 중요합니다. 이전 프레임과 현재 프레임 사이의 시간 간격인데, 이걸 곱하지 않으면 60fps 컴퓨터에서는 빠르게, 30fps 컴퓨터에서는 느리게 움직이는 문제가 생깁니다.
(저도 처음에 이걸 몰라서 "내 컴퓨터에선 잘 되는데 왜 다른 컴퓨터에선 이상하지?" 했던 기억이 있습니다)
FixedUpdate() - 고정 간격 호출
특징
FixedUpdate는 고정된 시간 간격으로 호출됩니다. 기본값은 0.02초(초당 50번)입니다.
프레임 레이트와 무관하게 일정한 간격을 유지합니다:
- 60fps든 30fps든 → 초당 50번 호출 (기본 설정)
언제 사용하나요?
- Rigidbody를 이용한 물리 이동
- 힘(Force) 적용
- 물리 기반 점프
private Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
// 물리 이동은 FixedUpdate에서
float horizontal = Input.GetAxis("Horizontal");
rb.AddForce(Vector3.right * horizontal * force);
}
왜 물리는 FixedUpdate인가요?
물리 엔진은 시간 간격이 일정해야 정확한 계산이 가능합니다. Update처럼 불규칙한 간격으로 물리 연산을 하면, 프레임 드랍 시 캐릭터가 벽을 뚫고 지나가거나 이상한 방향으로 튀는 현상이 발생합니다.
유니티의 물리 엔진(PhysX)이 FixedUpdate 직후에 실행되기 때문에, 물리 관련 코드는 여기에 넣어야 합니다.
LateUpdate() - Update 이후 호출
특징
LateUpdate는 모든 Update가 끝난 후에 호출됩니다.
언제 사용하나요?
주로 카메라 추적에 사용합니다.
// 카메라가 플레이어를 따라다니는 스크립트
void LateUpdate()
{
// 플레이어의 Update 이동이 끝난 후 카메라 위치 갱신
transform.position = player.position + offset;
}
왜 Update가 아니라 LateUpdate일까요? 카메라가 Update에서 위치를 갱신하면, 플레이어보다 먼저 실행될 수 있습니다. 그러면 플레이어는 이동했는데 카메라는 이전 위치를 따라가서 화면이 덜덜 떨리는 현상이 생깁니다.
정리: 언제 뭘 써야 하나요?
| 함수 | 호출 타이밍 | 용도 |
|---|---|---|
Update |
매 프레임 (불규칙) | 입력 처리, UI, 비물리 로직 |
FixedUpdate |
고정 간격 (0.02초) | Rigidbody 물리 연산 |
LateUpdate |
Update 이후 | 카메라 추적 |
실수하기 쉬운 패턴
// ❌ 잘못된 예: 물리 이동을 Update에서
void Update()
{
rb.AddForce(Vector3.forward * force); // 프레임 드랍 시 불안정
}
// ✅ 올바른 예: 물리 이동은 FixedUpdate에서
void FixedUpdate()
{
rb.AddForce(Vector3.forward * force);
}
// ❌ 잘못된 예: 입력 처리를 FixedUpdate에서
void FixedUpdate()
{
if (Input.GetKeyDown(KeyCode.Space)) // 입력 누락 가능
{
Jump();
}
}
// ✅ 올바른 예: 입력은 Update에서 받고, 물리는 FixedUpdate에서
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
shouldJump = true;
}
}
void FixedUpdate()
{
if (shouldJump)
{
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
shouldJump = false;
}
}
마무리
정리하면:
- Update: 입력과 일반 로직
- FixedUpdate: 물리 연산
- LateUpdate: 카메라 등 후처리
사실 저도 지금까지 "대충 Update에 다 넣어도 돌아가긴 하니까"라는 마음으로 코드를 짠 적이 많습니다. 하지만 물리 기반 게임을 만들거나, 다양한 사양의 기기에서 테스트해보면 이 차이가 확실히 느껴집니다.
다음 글에서는 Time.deltaTime과 Time.fixedDeltaTime의 차이, 그리고 FixedUpdate의 호출 주기를 조정하는 방법을 알아보겠습니다.

더 공부하고 싶다면?
이 글에서 다룬 내용을 영상으로 더 깊이 배우고 싶으시다면, 아래 강의를 추천드립니다:
완전 처음이라면:
- 레트로의 유니티 C# 게임 프로그래밍 에센스 - 유튜브 인기 강사 이제민님의 체계적인 기초 강의
체계적으로 MMORPG까지 도전하고 싶다면:
- Rookiss의 C#과 유니티로 만드는 MMORPG 게임 개발 시리즈 - 前 크래프톤/NC 개발자의 실무 노하우
Reference
'유니티 > 스크립트' 카테고리의 다른 글
| 유니티 Rest API 통신 UnityWebRequest (0) | 2021.07.01 |
|---|---|
| 유니티 특정 시간동안 조건을 유지할 경우 (0) | 2020.12.25 |
| [유니티] npc와 대화하기 UniRX (1) | 2020.12.24 |
| [유니티]공 이동거리 계산 프로그램 (0) | 2020.08.02 |
| [유니티]오브젝트 순차적 색상변경 (0) | 2020.08.02 |