This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this manual in English
Defold 어플리케이션이나 게임의 라이프사이클은 큰 흐름에서 단순합니다. 엔진은 초기화, 업데이트 루프(앱과 게임이 대부분의 시간을 보내는 곳), 마무리라는 세 실행 단계를 거칩니다.
이 매뉴얼은 Defold 1.12.0 버전부터의 동작을 기준으로 합니다. 1.12.0에서는 라이프사이클 관련 변경사항과 새로운 late_update() 함수가 도입되었습니다.

대부분의 경우 Defold 내부 동작은 기본적인 수준만 이해해도 충분합니다. 하지만 Defold가 작업을 수행하는 정확한 순서가 중요한 예외 상황을 만날 수도 있습니다. 이 문서는 엔진이 어플리케이션을 시작부터 끝까지 실행하는 방식을 설명합니다.
어플리케이션은 엔진 실행에 필요한 모든 것을 초기화하면서 시작합니다. main 컬렉션을 로드하고, init() Lua 함수가 있는 로드된 모든 컴포넌트(스크립트 컴포넌트와 GUI 스크립트가 있는 GUI 컴포넌트)에서 init()을 호출합니다. 이를 통해 커스텀 초기화를 수행할 수 있습니다.
그다음 어플리케이션은 전체 수명 대부분을 보내는 업데이트 루프에 진입합니다. 각 프레임마다 게임 오브젝트와 그 안에 포함된 컴포넌트가 업데이트됩니다. 스크립트와 GUI 스크립트의 update() 함수가 호출됩니다. 업데이트 루프 중에는 메세지가 수신자에게 디스패치되고, 사운드가 재생되며, 모든 그래픽이 렌더링됩니다.
어느 시점에는 어플리케이션의 라이프사이클이 끝납니다. 어플리케이션이 종료되기 전에 엔진은 업데이트 루프를 빠져나와 마무리 단계에 들어갑니다. 로드된 모든 게임 오브젝트가 삭제될 수 있도록 준비합니다. 모든 오브젝트 컴포넌트의 final() 함수가 호출되어 커스텀 정리 작업을 수행할 수 있습니다. 그런 다음 오브젝트가 삭제되고 main 컬렉션이 언로드됩니다.
“dispatch messages” 패스에 포함된 단계는 명확성을 위해 이 매뉴얼 끝의 별도 다이어그램에 표시되어 있으며, 다이어그램에서는 작은 “화살표가 있는 봉투” 아이콘 📩으로 표시됩니다.
여기서 게임이 시작되며, 실행 중인 게임의 첫 번째 단계입니다. 이 단계는 3개의 단계로 나눌 수 있습니다.

Preinitialization 단계 동안 엔진은 main(bootstrap) 컬렉션을 로드하기 전에 많은 작업을 수행합니다. 메모리 프로파일러, 소켓, 그래픽, HID(입력 디바이스), 사운드, 물리 등을 설정합니다. 어플리케이션 설정(game.project)도 로드하고 설정합니다.

엔진 초기화가 끝날 때 사용자가 제어할 수 있는 첫 번째 진입점은 현재 렌더 스크립트의 init() 함수 호출입니다.
그런 다음 main 컬렉션이 로드되고 초기화됩니다.
Collection Init 단계 동안 컬렉션의 모든 게임 오브젝트는 자식에게 자신의 변형(transform)을 적용합니다. 여기에는 이동(위치 변경), 회전, 확대/축소가 포함됩니다. 그런 다음 존재하는 모든 컴포넌트의 init() 함수가 호출됩니다.

게임 오브젝트 컴포넌트의 init() 함수가 호출되는 순서는 지정되어 있지 않습니다. 엔진이 같은 컬렉션에 속한 오브젝트를 특정 순서로 초기화한다고 가정하면 안 됩니다.
그런 다음 엔진은 전체 Post Update 패스를 수행합니다. 이는 나중에 각 Update Loop 단계 뒤에 수행되는 것과 같은 패스입니다. init() 코드가 새 메세지를 게시하고, 팩토리에 새 오브젝트 스폰을 지시하고, 오브젝트를 삭제 대상으로 표시하는 등 다른 동작을 수행할 수 있기 때문에 초기화 끝에서 이 패스가 수행됩니다.

이 패스는 메세지 전달, 실제 팩토리 게임 오브젝트 스폰, 오브젝트 삭제를 수행합니다. Post Update 패스에는 큐에 쌓인 메세지를 전달할 뿐만 아니라 컬렉션 프록시로 보낸 메세지도 처리하는 “dispatch messages” 시퀀스가 포함된다는 점에 주의하세요. 이후의 프록시 업데이트(활성화, 비활성화, 초기화, 마무리, 로딩, 언로드 표시)는 이 단계들 중에 수행됩니다.
init() 중에 컬렉션 프록시를 로드하고, 그 안의 모든 오브젝트가 초기화되도록 한 다음, 프록시를 통해 컬렉션을 언로드하는 것도 완전히 가능합니다. 이 모든 작업은 첫 번째 컴포넌트 update()가 호출되기 전, 즉 엔진이 초기화 단계를 떠나 업데이트 루프에 들어가기 전에 일어납니다.
function init(self)
print("init()")
msg.post("#collectionproxy", "load")
end
function update(self, dt)
-- 이 코드에 도달하기 전에 프록시 컬렉션이 언로드됩니다.
print("update()")
end
function on_message(self, message_id, message, sender)
if message_id == hash("proxy_loaded") then
print("proxy_loaded. Init, enable and then unload.")
msg.post("#collectionproxy", "init")
msg.post("#collectionproxy", "enable")
msg.post("#collectionproxy", "unload")
-- 이 오브젝트의 update()에 도달하기 전에
-- 프록시 컬렉션 오브젝트의 init() 및 final() 함수가 호출됩니다.
end
end
Update Loop는 프레임마다 한 번씩 특정 시퀀스를 실행합니다. 이 시퀀스는 5개의 주요 단계로 정의할 수 있습니다.

입력은 사용 가능한 디바이스에서 읽히고, 입력 바인딩에 매핑된 뒤 디스패치됩니다. 입력 포커스를 획득한 게임 오브젝트는 그 안의 모든 컴포넌트 on_input() 함수로 입력을 보냅니다. 스크립트 컴포넌트와 GUI 스크립트가 있는 GUI 컴포넌트를 가진 게임 오브젝트는, 두 함수가 정의되어 있고 입력 포커스를 획득했다면 두 컴포넌트의 on_input() 함수 모두에 입력을 받습니다.

입력 포커스를 획득하고 컬렉션 프록시 컴포넌트를 포함한 게임 오브젝트는 프록시 컬렉션 안의 컴포넌트에도 입력을 디스패치합니다. 이 과정은 활성화된 컬렉션 프록시 안의 활성화된 컬렉션 프록시를 따라 재귀적으로 계속됩니다.
Update 단계는 Update Loop의 일부입니다. 루트 컬렉션에서 한 번 시작되고, 이후 활성화된 각 컬렉션 프록시에 대해 재귀적으로 실행됩니다.
컬렉션 안에서 Defold는 컴포넌트 타입별로 콜백을 처리합니다. 관련 단계를 구현한 컴포넌트 타입의 모든 인스턴스를 순회하고, 각 인스턴스에 대해 Lua 콜백을 호출하고, 메세지를 플러시한 뒤 다음 컴포넌트 타입으로 이동합니다.
고수준에서 script 컴포넌트 Lua 콜백 단계의 순서는 다음과 같습니다.
fixed_update() - 프레임당 0..N번 호출됩니다(고정 타임스텝을 사용하는 경우).update() - 프레임당 1번 호출됩니다.late_update() - 프레임당 1번 호출됩니다.
main 컬렉션의 각 게임 오브젝트 컴포넌트가 순회됩니다. 이 컴포넌트 중 fixed_update()/update()/late_update() 함수가 있는 스크립트를 가진 것이 있으면 해당 함수가 호출됩니다. 컴포넌트가 컬렉션 프록시라면 프록시 컬렉션의 각 컴포넌트가 Update 단계의 모든 절차에 따라 재귀적으로 업데이트됩니다.
게임 오브젝트 컴포넌트의 update() 함수가 호출되는 순서는 지정되어 있지 않습니다. 엔진이 같은 컬렉션에 속한 오브젝트를 특정 순서로 업데이트한다고 가정하면 안 됩니다. fixed_update()와 late_update()(1.12.0부터)도 마찬가지입니다.
충돌 오브젝트 컴포넌트의 경우 물리 메세지(충돌, 트리거, ray cast 응답 등)는 이를 포함하는 게임 오브젝트 전체에 디스패치되어, on_message() 함수가 있는 스크립트를 포함한 모든 컴포넌트로 전달됩니다.
물리 시뮬레이션에 고정 타임스텝을 사용하는 경우 모든 스크립트 컴포넌트에서 fixed_update() 함수가 호출될 수도 있습니다. 이 함수는 안정적인 물리 시뮬레이션을 얻기 위해 일정한 간격으로 물리 오브젝트를 조작하고 싶은 물리 기반 게임에서 유용합니다.
Update Loop 중 필요한 경우 각 컴포넌트 타입 업데이트 전에 여러 번 변형이 업데이트되어, 게임 오브젝트의 이동, 회전, 확대/축소가 각 게임 오브젝트 컴포넌트와 자식 게임 오브젝트 컴포넌트에 적용됩니다.
필요한 경우 Update Loop 끝에서 추가로 한 번 최종 변형 업데이트가 수행됩니다.
아래 표는 엔진 레벨 업데이트 패스를 설명합니다. 정확한 내부 컴포넌트 우선순위 순서(엔진 구현 세부사항)는 의도적으로 생략하지만, 스크립팅과 관련된 순서 보장은 반영합니다.
fixed_update()는 update()보다 먼저 실행됩니다.late_update()는 update() 뒤에 실행됩니다.Use Fixed Timestep이 false이거나 Fixed Update Frequency가 0이면 단계 시작 시 dt를 준비한 뒤 아래 표와 같은 흐름으로 진행됩니다.
:::sidenote 각 컴포넌트 타입 업데이트 뒤에는 모든 메세지가 디스패치됩니다. 표를 깔끔하게 유지하기 위해 아래 표에는 표시하지 않았습니다. :::
| 단계 | 엔진 단계 | Lua 콜백 | 설명 |
|---|---|---|---|
| 1 | Update | update() |
내부 우선순위 순서에서 Update를 구현한 각 컴포넌트 타입마다 프레임당 한 번 호출됩니다. 또한 go.animate()로 시작된 GO 프로퍼티 애니메이션은 별도 컴포넌트 타입으로 여기서 업데이트됩니다. Physics 컴포넌트도 여기서 업데이트됩니다. 활성화된 각 컬렉션 프록시에 대해서는 전체 Update 단계가 1단계부터 재귀적으로 호출됩니다. |
| 2 | Late Update | late_update() |
내부 우선순위 순서에서 Late Update를 구현한 각 컴포넌트 타입마다 프레임당 한 번 호출됩니다. |
| 3 | Transforms | 필요한 경우 끝에서 각 컴포넌트에 대해 추가 최종 변형 업데이트가 한 번 수행됩니다. |
Use Fixed Timestep이 true이고 Fixed Update Frequency가 0이 아니면, 단계 시작 시 dt(delta time), fixed_dt, num_fixed_steps(0..N)를 준비합니다. 즉 마지막 업데이트 이후의 시간을 바탕으로 고정된 양의 업데이트가 수행되도록 고정 업데이트가 몇 번 호출될지 결정합니다.
:::sidenote 각 컴포넌트 타입 업데이트 뒤에는 모든 메세지가 디스패치됩니다. 표를 깔끔하게 유지하기 위해 아래 표에는 표시하지 않았습니다. :::
그런 다음 반복합니다.
| 단계 | 엔진 단계 | Lua 콜백 | 설명 |
|---|---|---|---|
| 1 | Fixed Update | fixed_update() |
내부 우선순위 순서에서 Fixed Update를 구현한 각 컴포넌트 타입마다 타이밍에 따라 프레임당 0..N번 호출됩니다. 여기에는 Physics 컴포넌트 Fixed Update 단계가 포함됩니다. |
| 2 | Update | update() |
내부 우선순위 순서에서 Update를 구현한 각 컴포넌트 타입마다 프레임당 한 번 호출됩니다. 또한 go.animate()로 시작된 GO 프로퍼티 애니메이션은 별도 컴포넌트 타입으로 여기서 업데이트됩니다. 활성화된 각 컬렉션 프록시에 대해서는 Update 단계가 1단계부터 재귀적으로 호출됩니다. |
| 3 | Late Update | late_update() |
내부 우선순위 순서에서 Late Update를 구현한 각 컴포넌트 타입마다 프레임당 한 번 호출됩니다. |
| 4 | Transforms | 필요한 경우 끝에서 각 컴포넌트에 대해 추가 최종 변형 업데이트가 한 번 수행됩니다. |
Defold가 Update 단계 동안 내부적으로 어떻게 동작하는지 더 자세히 알아야 한다면 gameobject.cpp 코드를 직접 읽어볼 가치가 있습니다.
렌더 업데이트 블록은 먼저 @render 소켓으로 보낸 모든 메세지(예: 카메라 컴포넌트 set_view_projection 메세지, set_clear_color 메세지 등)를 디스패치합니다. 그런 다음 렌더 스크립트 update()가 호출됩니다.

업데이트 뒤에는 post update 시퀀스가 실행됩니다. 이 시퀀스는 언로드 대상으로 표시된 컬렉션 프록시를 메모리에서 언로드합니다(이는 “dispatch messages” 시퀀스 중에 발생합니다). 삭제 대상으로 표시된 게임 오브젝트는, 존재하는 경우 모든 컴포넌트의 final() 함수를 호출합니다. final() 함수의 코드는 종종 큐에 새 메세지를 게시하므로, 그 뒤에 “dispatch messages” 패스가 실행됩니다.

게임 오브젝트를 스폰하라는 지시를 받은 팩토리 컴포넌트가 다음으로 해당 작업을 수행합니다. 마지막으로 삭제 대상으로 표시된 게임 오브젝트가 실제로 삭제됩니다.
업데이트 루프의 마지막 단계는 @system 메세지(exit, reboot 메세지, 프로파일러 토글, 비디오 캡처 시작 및 중지 등)를 디스패치하는 일을 포함합니다.

그런 다음 그래픽이 렌더링되며, 비주얼 프로파일러 렌더링도 함께 수행됩니다(디버깅 문서 참조). 그래픽 렌더링 뒤에는 비디오 캡처가 수행됩니다.
초당 프레임 업데이트 수(초당 업데이트 루프 실행 횟수와 같음)는 프로젝트 설정에서 설정하거나, @system 소켓에 set_update_frequency 메세지를 보내 프로그래밍 방식으로 설정할 수 있습니다. 또한 프록시에 set_time_step 메세지를 보내 컬렉션 프록시별로 time step(타임스텝)을 개별 설정할 수 있습니다. 컬렉션의 타임스텝을 변경해도 프레임 레이트에는 영향을 주지 않습니다. 대신 물리 업데이트 타임스텝과 update()에 전달되는 dt 변수에는 영향을 줍니다. 또한 타임스텝을 변경해도 각 프레임에서 update()가 호출되는 횟수는 바뀌지 않습니다. 항상 정확히 한 번만 호출됩니다.
(자세한 내용은 컬렉션 프록시 매뉴얼과 set_time_step을 참조하세요.)
Defold 1.12.0에서는 입력 감지는 계속하면서 엔진 업데이트와 렌더링을 완전히 건너뛸 수 있는 엔진 스로틀링 API가 도입되었습니다. 어떤 입력이든 발생하면 엔진이 다시 깨어나며, 쿨다운이 지난 뒤에 엔진은 다시 스로틀링 상태로 들어갈 수 있습니다.
자세한 내용과 사용 예제는 sys.set_engine_throttle() API를 참조하세요.
어플리케이션이 종료될 때는 먼저 마지막 업데이트 루프 시퀀스를 끝냅니다. 이 과정에서 모든 컬렉션 프록시가 언로드되고 각 프록시 컬렉션의 모든 게임 오브젝트가 마무리되고 삭제됩니다.
이 작업이 끝나면 엔진은 main 컬렉션과 그 오브젝트를 처리하는 마무리 시퀀스에 들어갑니다.

먼저 컴포넌트 final() 함수가 호출됩니다. 이어서 메세지 디스패치가 수행됩니다. 마지막으로 모든 게임 오브젝트가 삭제되고 main 컬렉션이 언로드됩니다.
그런 다음 엔진은 내부적으로 서브시스템 종료를 진행합니다. 프로젝트 설정이 삭제되고, 메모리 프로파일러가 종료되는 등의 작업이 수행됩니다.
이제 어플리케이션이 완전히 종료되었습니다.
Dispatching Messages는 각 컴포넌트 타입 업데이트 뒤에 수행되는 특수 패스입니다. 예를 들어 스프라이트 업데이트, 스크립트 업데이트, 그 밖에 메세지를 보낼 수 있는 모든 동작 뒤에 수행됩니다. 실행 중에는 큐에 모인 모든 게시된 메세지가 디스패치됩니다. 다이어그램에서는 작은 “화살표가 있는 봉투” 아이콘 📩으로 표시됩니다.

모든 사용자 메세지가 각 컴포넌트의 on_message() 호출로 디스패치된 뒤에는, 각 컬렉션 프록시에 대해 Defold 특수 메세지가 다음 순서(다이어그램에도 표시된 순서)로 처리됩니다.
load 메세지 - 로딩 대상으로 표시된 컬렉션 프록시를 로드하고, proxy_loaded 메세지를 다시 게시합니다.unload 메세지 - 언로드 대상으로 표시된 컬렉션 프록시를 언로드하고, proxy_unloaded 메세지를 다시 게시합니다.init 메세지 - 초기화될 모든 컬렉션 프록시에 대해 Collection Init 단계를 트리거합니다.final 메세지 - 마무리 대상으로 표시된 프록시의 모든 컴포넌트에서 final()을 트리거합니다.enable 메세지 - 컬렉션 프록시를 활성화하여 다음 프레임부터 해당 프록시에 대해 Update Loop가 수행되도록 합니다. 이 동작은 컬렉션의 각 컴포넌트에 대해 암묵적으로 init()을 트리거합니다.disable 메세지 - 컬렉션 프록시를 비활성화하여 다음 프레임부터 해당 프록시에 대해 Update Loop가 수행되지 않도록 합니다. 해당 프록시의 Update Loop 실행을 완전히 중지합니다.수신 컴포넌트의 on_message() 코드가 추가 메세지를 게시할 수 있으므로, 메세지 전달자는 메세지 큐가 비워질 때까지 게시된 메세지를 재귀적으로 계속 디스패치합니다. 다만 메세지 전달자가 메세지 큐를 반복 처리하는 횟수에는 제한이 있습니다. 자세한 내용은 메세지 체인을 참조하세요.