게임은 멈춰 있는 것처럼 보여도 내부에서는 쉬지 않고 같은 작업을 되풀이합니다. 이 반복 구조를 게임 루프라고 하고, 한 번 반복해 화면을 한 장 그리는 단위를 프레임이라고 합니다. 이 글에서는 게임 루프와 프레임의 관계, 그리고 프레임 속도가 달라도 게임이 같은 속도로 움직이게 하는 방법을 설명합니다.
게임 루프의 기본 구조
가장 단순한 게임 루프는 세 단계를 반복합니다. 플레이어 입력을 읽고, 게임 상태를 갱신하고, 화면을 그립니다. 게임이 끝날 때까지 이 과정을 계속 되풀이합니다.
- 입력 처리: 키보드, 마우스, 터치, 패드 입력을 읽습니다.
- 갱신(Update): 캐릭터 이동, 충돌 확인, AI 판단, 타이머 진행 등 게임 세계를 한 단계 진행합니다.
- 렌더링(Render): 갱신된 상태를 바탕으로 화면에 그립니다.
일반 프로그램은 사용자가 무언가를 할 때까지 기다리지만, 게임은 입력이 없어도 몬스터가 움직이고 시간이 흐릅니다. 그래서 기다리지 않고 계속 도는 루프가 필요합니다.
프레임과 FPS
FPS(Frames Per Second)는 1초에 화면을 몇 장 그리는지를 뜻합니다. 60FPS라면 한 프레임에 쓸 수 있는 시간은 약 16.7밀리초입니다. 이 시간 안에 입력, 갱신, 렌더링을 모두 끝내야 화면이 매끄럽게 이어집니다.
한 프레임 처리가 정해진 시간을 넘기면 프레임이 떨어지고, 화면이 끊기거나 조작이 늦게 반응하는 느낌이 납니다. 최적화 작업은 결국 이 프레임 예산 안에 일을 맞추는 작업이라고 할 수 있습니다.
모니터가 화면을 바꾸는 주기와 게임이 그림을 내보내는 주기가 어긋나면 화면 위아래가 엇갈려 보이는 찢어짐 현상이 생깁니다. 수직 동기화(V-Sync)는 그림을 내보내는 시점을 모니터 주기에 맞춰 이 문제를 줄이는 기능이며, 대신 입력이 조금 늦게 느껴질 수 있습니다.
델타 타임: 컴퓨터 성능과 상관없이 같은 속도로
캐릭터를 매 프레임 1칸씩 움직이면, 빠른 컴퓨터에서는 캐릭터도 빨라지고 느린 컴퓨터에서는 느려집니다. 이를 막기 위해 직전 프레임부터 지금까지 흐른 시간인 델타 타임을 곱합니다. '1초에 5칸 이동'을 원하면 이동량을 '5 × 델타 타임'으로 계산하는 식입니다.
유니티의 Time.deltaTime, 언리얼의 DeltaSeconds가 이 값입니다. 이동, 회전, 쿨타임처럼 시간에 따라 변하는 값에는 거의 항상 델타 타임이 들어간다고 생각하면 됩니다.
고정 시간 갱신과 가변 시간 갱신
| 방식 | 설명 | 주로 쓰는 곳 |
|---|---|---|
| 가변 시간 갱신 | 프레임마다 실제 흐른 시간만큼 진행 | 일반 이동, 애니메이션, UI |
| 고정 시간 갱신 | 정해진 간격으로 일정하게 진행, 밀리면 여러 번 실행 | 물리 계산, 네트워크 동기화, 결정론적 시뮬레이션 |
물리 계산은 시간 간격이 들쭉날쭉하면 결과가 불안정해지고, 빠른 물체가 벽을 뚫고 지나가는 문제도 생깁니다. 그래서 엔진은 물리를 고정 간격으로 따로 돌립니다. 유니티의 FixedUpdate가 그 예입니다. 입력은 Update에서 받고 물리 힘은 FixedUpdate에서 주는 식으로 역할을 나눕니다.
프레임이 떨어지는 흔한 원인
- 매 프레임 새 객체를 많이 만들어 메모리 정리가 자주 일어남
- 모든 적이 매 프레임 서로의 거리를 전부 계산함
- 화면에 그릴 물체가 너무 많아 드로우콜이 늘어남
- 무거운 작업(파일 읽기, 길찾기)을 한 프레임에 몰아서 처리함
무거운 작업은 여러 프레임에 나눠 처리하거나, 결과를 미리 계산해 두는 방식으로 줄입니다. 어디가 느린지는 추측하지 말고 엔진 프로파일러로 측정해 확인하는 것이 기본입니다.
직접 확인해 보기
엔진 없이 콘솔이나 WinAPI로 간단한 게임 루프를 만들어 보면 엔진이 대신 해 주던 일이 보입니다. 델타 타임을 쓰지 않은 버전과 쓴 버전을 비교하고, FPS를 일부러 제한해 차이를 관찰해 보세요.
SBS아카데미게임학원 게임프로그래밍 과정은 C·C++ 이후 WinAPI 기초와 응용을 다루어, 엔진 아래에서 돌아가는 구조를 직접 경험해 볼 수 있습니다.
자주 묻는 질문
FPS는 높을수록 무조건 좋은가요?
화면은 매끄러워지지만 기기 발열과 배터리 소모가 늘어납니다. 모바일 게임은 장르에 따라 FPS를 제한하거나 설정에서 고르게 하는 경우가 많습니다.
Update와 FixedUpdate 중 어디에 코드를 써야 하나요?
물리 엔진에 힘을 주거나 속도를 바꾸는 코드는 FixedUpdate, 입력 확인과 일반 로직은 Update에 두는 것이 일반적인 기준입니다.
