[Godot, 토막글] Process와 Physics Process

김낭만·2024년 11월 24일

결론만 보기

서론

요즘 취미 삼아 고도엔진(Godot Engine)을 공부하고 있다.

국내에도 몇 있는 고도엔진 튜토리얼을 살펴보면 알 수 있듯이, 고도에서는 각 노드의 _process()_physics_process()를 이용해 주기적으로 처리되어야 하는 로직을 구현할 수 있다.

그런데 이 둘은 어떻게 다른 걸까?

본론

Idle Processing과 Physics Processing

해당 주제와 관련된 고도의 공식 문서에서는, Idle Processing과 Physics Processing에 대해 설명하고 있다.

Idle Processing은 매 프레임 실행된다.
60FPS에서는 1초에 60번, 30FPS에서는 1초에 30번 실행된다는 것을 의미한다.
즉, Idle Processing은 기기 환경이나 최적화에 따라 실행 주기가 가변적이다.

Physics Processing은 매 Physics Frame마다 실행된다.
Physics Frame은 실제 프레임과 무관하게 물리 연산이 일어나는 시기를 의미한다.
Physics Frame의 기본값은 초당 60번이다.
즉 Physics Processing은 안정적인 60FPS의 Idle Processing과 동일한 주기로 일어난다.

Idle Processing은 _process() 메서드,
Physics Processing은 _physics_process() 메서드에 의해 일어난다.

정리해보자.

  • Idle Processing(_process)은 매 프레임 실행되고, 따라서 가변적이다.
  • Physics Processing(_physics_process)은 프로젝트 내 고정적인 주기로 실행된다.

Physics Processing을 사용하는 이유

그렇다면 왜 고정적인 주기로 실행되는 Physics Processing이 필요할까?

당연히 물리(Physics)의 동작은 프레임과는 별개로 이루어져야 된다.
물리는 FPS와 무관하게, 일정하게 작동해야 하기 때문이다.

오해 하나는 짚고 넘어가자

그런데, _process_physics_process는 모두 delta를 매개변수로 갖는다.
delta는 이전에 해당 함수가 일어난 이후 지난 시간을 의미한다.
예를 들어, 60FPS에서 _processdelta1/60초를 의미할 것이다.

사실 이 delta를 이용해 _process의 동작을 일정하게 만들 수 있다.
프레임률이 달라져 _process의 실행 주기가 바뀐다면, 그만큼 delta의 값도 변하기 때문에 이를 반영할 수 있기 때문이다.

(그래서 일부 블로그 등지에 등장하는, _process를 사용하면 프레임률마다 캐릭터 이동속도가 바뀌니 뭐니 하는 말은 사실 옳은 이야기는 아니다.)

Physics Processing을 사용하는 진짜 이유

다만, 그럼에도 불구하고 _physics_process를 사용하는 이유는 아래와 같다.

  1. 프레임률이 Physics Processing의 주기보다 떨어지면, 의도한 것보다 덜 빈번한 물리 연산이 이루어진다.
  2. Physics Processing은 실제 물리의 작동(Physics Step)보다 먼저 일어나지만, Idle Processing은 Physics Step 이후에 일어날 수 있다.

전자는 생각해보면 간단한 이야기다.
초당 60번 일어나야 하는 물리 연산이 있다고 하자. _process를 사용해서 이 연산을 구현하면 낮은 프레임률, 이를테면 30FPS에서는 이 연산이 30번밖에 이뤄지지 않는다.
물론, delta를 이용해 값 자체는 보정할 수 있지만, 연산이 가변적인 간격에 의해 이루어지고, 최소 주기를 보장할 수 없기 때문에 불안정한 결과를 낳을 수 있다.

후자의 Physics Step은 충돌 등 고도 엔진의 물리 작동이 일어나는 단계이다.
이를테면 어떤 물체의 이동을 구현했다고 하자.
그렇다면 이 물체는 이동한 다음에 충돌 이벤트를 발생시키는 것이 바람직할 것이다.
매 루프마다 물체가 충돌을 먼저 체크하고, 그 이후 이동이 일어난 다음, 그 이동에 대한 충돌 판정은 다음 루프에서 일어난다고 생각해보자. 직관성도 떨어지고 의도치 않은 결과를 내놓을 수도 있다.
_physics_process는 매 Physical Step 이전에 호출된다. 반면, _process는 싱글스레드 환경의 경우 Physical Step 이후에 호출된다.

따라서

_process_physics_process의 사용처는 아래와 같이 결정할 수 있다.

  1. 화면의 갱신 주기(프레임률)마다 갱신되어야 하는 것(시각적 요소)은 _process에 구현한다.
  2. 고정적으로 호출되어야 하는 것(물리 등)은 _physics_process에 구현한다.

결론

  1. Idle Processing(_process)은 프레임률과 동기화되어 일어나고, 따라서 시각적 요소 처리에 사용한다.
  2. Physics Processing(_physics_process)은 해당 프로젝트의 설정에 의해 고정되어 있으므로 안정적인 물리 처리 등을 위해 사용한다.
  3. 두 메소드 모두 호출 간격을 나타내는 매개변수 delta를 갖는다.
  4. 싱글스레드 환경에서, 매 루프의 순서는 Physics Processing, Physics Step, Idle Processing이다.

참조

Idle and Physics Processing - Godot Docs 4.3
Difference between _process() and _physics_process() - 고도엔진 포럼

profile
재밌거나 필요하다고 생각하는 것을 만듭니다.

0개의 댓글