目录
代码版本4.1.0
1、文件夹结构
-core:游戏引擎核心,包括容器、类型、数学、操作系统、内存管理、节点资源帮助类等。
-drivers:驱动,尤其是跨平台驱动封装。
-editor:引擎编辑器的界面交互。
-main:引擎生存周期管理。
-misc:其它杂项。
-modules:模块。
-platform:平台。
-scene:2D/3D场景。
-servers:辅助服务,如物理和音频。
-tests:单元测试。
-thirdparty:项目依赖的第三方库。
2、程序运行流程
以windows为例,首先启动文件\platform\windows\godot_windows.cpp中的:
int main(int argc, char **argv)
函数,Godot会根据平台不同,进行不同的启动流程,这个操作封装在/main/main.h中。
在main函数中,经过两层调用进入:
int widechar_main(int argc, wchar_t **argv)
然后检测当前操作系统:
OS_Windows os(nullptr);
接着进行setup:
Error err = Main::setup(argv_utf8[0], argc - 1, &argv_utf8[1]);
然后执行:
if (Main::start()) {
os.run();
}
Main::cleanup();
进入程序主循环:
void OS_Windows::run() {
if (!main_loop) {
return;
}
main_loop->initialize();
while (true) {
DisplayServer::get_singleton()->process_events(); // get rid of pending events
if (Main::iteration()) {
break;
}
}
main_loop->finalize();
}
其中:
DisplayServer::get_singleton()->process_events(); 负责清除挂起的事件
Main::iteration()为引擎主循环。
3、主循环分析
主循环作为引擎的主体,代码稍有些长:
bool Main::iteration() {
//for now do not error on this
//ERR_FAIL_COND_V(iterating, false);
iterating++;
const uint64_t ticks = OS::get_singleton()->get_ticks_usec();
Engine::get_singleton()->_frame_ticks = ticks;
main_timer_sync.set_cpu_ticks_usec(ticks);
main_timer_sync.set_fixed_fps(fixed_fps);
const uint64_t ticks_elapsed = ticks - last_ticks;
const int physics_ticks_per_second = Engine::get_singleton()->get_physics_ticks_per_second();
const double physics_step = 1.0 / physics_ticks_per_second;
const double time_scale = Engine::get_singleton()->get_time_scale();
MainFrameTime advance = main_timer_sync.advance(physics_step, physics_ticks_per_second);
double process_step = advance.process_step;
double scaled_step = process_step * time_scale;
Engine::get_singleton()->_process_step = process_step;
Engine::get_singleton()->_physics_interpolation_fraction = advance.interpolation_fraction;
uint64_t physics_process_ticks = 0;
uint64_t process_ticks = 0;
uint64_t navigation_process_ticks = 0;
frame += ticks_elapsed;
last_ticks = ticks;
const int max_physics_steps = Engine::get_singleton()->get_max_physics_steps_per_frame();
if (fixed_fps == -1 && advance.physics_steps > max_physics_steps) {
process_step -= (advance.physics_steps - max_physics_steps) * physics_step;
advance.physics_steps = max_physics_steps;
}
bool exit = false;
// process all our active interfaces
XRServer::get_singleton()->_process();
for (int iters = 0; iters < advance.physics_steps; ++iters) {
if (Input::get_singleton()->is_using_input_buffering() && agile_input_event_flushing) {
Input::get_singleton()->flush_buffered_events();
}
Engine::get_singleton()->_in_physics = true;
uint64_t physics_begin = OS::get_singleton()->get_ticks_usec();
PhysicsServer3D::get_singleton()->sync();
PhysicsServer3D::get_singleton()->flush_queries();
PhysicsServer2D::get_singleton()->sync();
PhysicsServer2D::get_singleton()->flush_queries();
if (OS::get_singleton()->get_main_loop()->physics_process(physics_step * time_scale)) {
PhysicsServer3D::get_singleton()->end_sync();
PhysicsServer2D::get_singleton()->end_sync();
exit = true;
break;
}
uint64_t navigation_begin = OS::get_singleton()->get_ticks_usec();
NavigationServer3D::get_singleton()->process(physics_step * time_scale);
navigation_process_ticks = MAX(navigation_process_ticks, OS::get_singleton()->get_ticks_usec() - navigation_begin); // keep the largest one for reference
navigation_process_max = MAX(OS::get_singleton()->get_ticks_usec() - navigation_begin, navigation_process_max);
message_queue->flush();
PhysicsServer3D::get_singleton()->end_sync();
PhysicsServer3D::get_singleton()->step(physics_step * time_scale);
PhysicsServer2D::get_singleton()->end_sync();
PhysicsServer2D::get_singleton()->step(physics_step * time_scale);
message_queue->flush();
physics_process_ticks = MAX(physics_process_ticks, OS::get_singleton()->get_ticks_usec() - physics_begin); // keep the largest one for reference
physics_process_max = MAX(OS::get_singleton()->get_ticks_usec() - physics_begin, physics_process_max);
Engine::get_singleton()->_physics_frames++;
Engine::get_singleton()->_in_physics = false;
}
if (Input::get_singleton()->is_using_input_buffering() && agile_input_event_flushing) {
Input::get_singleton()->flush_buffered_events();
}
uint64_t process_begin = OS::get_singleton()->get_ticks_usec();
if (OS::get_singleton()->get_main_loop()->process(process_step * time_scale)) {
exit = true;
}
message_queue->flush();
RenderingServer::get_singleton()->sync(); //sync if still drawing from previous frames.
if (DisplayServer::get_singleton()->can_any_window_draw() &&
RenderingServer::get_singleton()->is_render_loop_enabled()) {
if ((!force_redraw_requested) && OS::get_singleton()->is_in_low_processor_usage_mode()) {
if (RenderingServer::get_singleton()->has_changed()) {
RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands
Engine::get_singleton()->frames_drawn++;
}
} else {
RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands
Engine::get_singleton()->frames_drawn++;
force_redraw_requested = false;
}
}
process_ticks = OS::get_singleton()->get_ticks_usec() - process_begin;
process_max = MAX(process_ticks, process_max);
uint64_t frame_time = OS::get_singleton()->get_ticks_usec() - ticks;
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptServer::get_language(i)->frame();
}
AudioServer::get_singleton()->update();
if (EngineDebugger::is_active()) {
EngineDebugger::get_singleton()->iteration(frame_time, process_ticks, physics_process_ticks, physics_step);
}
frames++;
Engine::get_singleton()->_process_frames++;
if (frame > 1000000) {
// Wait a few seconds before printing FPS, as FPS reporting just after the engine has started is inaccurate.
if (hide_print_fps_attempts == 0) {
if (editor || project_manager) {
if (print_fps) {
print_line(vformat("Editor FPS: %d (%s mspf)", frames, rtos(1000.0 / frames).pad_decimals(2)));
}
} else if (print_fps || GLOBAL_GET("debug/settings/stdout/print_fps")) {
print_line(vformat("Project FPS: %d (%s mspf)", frames, rtos(1000.0 / frames).pad_decimals(2)));
}
} else {
hide_print_fps_attempts--;
}
Engine::get_singleton()->_fps = frames;
performance->set_process_time(USEC_TO_SEC(process_max));
performance->set_physics_process_time(USEC_TO_SEC(physics_process_max));
performance->set_navigation_process_time(USEC_TO_SEC(navigation_process_max));
process_max = 0;
physics_process_max = 0;
navigation_process_max = 0;
frame %= 1000000;
frames = 0;
}
iterating--;
// Needed for OSs using input buffering regardless accumulation (like Android)
if (Input::get_singleton()->is_using_input_buffering() && !agile_input_event_flushing) {
Input::get_singleton()->flush_buffered_events();
}
if (movie_writer) {
movie_writer->add_frame();
}
if ((quit_after > 0) && (Engine::get_singleton()->_process_frames >= quit_after)) {
exit = true;
}
if (fixed_fps != -1) {
return exit;
}
OS::get_singleton()->add_frame_delay(DisplayServer::get_singleton()->window_can_draw());
#ifdef TOOLS_ENABLED
if (auto_build_solutions) {
auto_build_solutions = false;
// Only relevant when running the editor.
if (!editor) {
OS::get_singleton()->set_exit_code(EXIT_FAILURE);
ERR_FAIL_V_MSG(true,
"Command line option --build-solutions was passed, but no project is being edited. Aborting.");
}
if (!EditorNode::get_singleton()->call_build()) {
OS::get_singleton()->set_exit_code(EXIT_FAILURE);
ERR_FAIL_V_MSG(true,
"Command line option --build-solutions was passed, but the build callback failed. Aborting.");
}
}
#endif
return exit;
}
主循环Main::iteration()分为以下几个主要部分:
帧率计算
物理引擎
输入处理
显示处理
脚本处理
音频处理
帧率计算
const uint64_t ticks = OS::get_singleton()->get_ticks_usec();
Engine::get_singleton()->_frame_ticks = ticks;
main_timer_sync.set_cpu_ticks_usec(ticks);
main_timer_sync.set_fixed_fps(fixed_fps);
const uint64_t ticks_elapsed = ticks - last_ticks;
const int physics_ticks_per_second = Engine::get_singleton()->get_physics_ticks_per_second();
const double physics_step = 1.0 / physics_ticks_per_second;
const double time_scale = Engine::get_singleton()->get_time_scale();
MainFrameTime advance = main_timer_sync.advance(physics_step, physics_ticks_per_second);
double process_step = advance.process_step;
double scaled_step = process_step * time_scale;
Engine::get_singleton()->_process_step = process_step;
Engine::get_singleton()->_physics_interpolation_fraction = advance.interpolation_fraction;
uint64_t physics_process_ticks = 0;
uint64_t process_ticks = 0;
uint64_t navigation_process_ticks = 0;
frame += ticks_elapsed;
last_ticks = ticks;
const int max_physics_steps = Engine::get_singleton()->get_max_physics_steps_per_frame();
if (fixed_fps == -1 && advance.physics_steps > max_physics_steps) {
process_step -= (advance.physics_steps - max_physics_steps) * physics_step;
advance.physics_steps = max_physics_steps;
}
bool exit = false;
物理引擎
XRServer::get_singleton()->_process();
for (int iters = 0; iters < advance.physics_steps; ++iters) {
if (Input::get_singleton()->is_using_input_buffering() && agile_input_event_flushing) {
Input::get_singleton()->flush_buffered_events();
}
Engine::get_singleton()->_in_physics = true;
uint64_t physics_begin = OS::get_singleton()->get_ticks_usec();
PhysicsServer3D::get_singleton()->sync();
PhysicsServer3D::get_singleton()->flush_queries();
PhysicsServer2D::get_singleton()->sync();
PhysicsServer2D::get_singleton()->flush_queries();
if (OS::get_singleton()->get_main_loop()->physics_process(physics_step * time_scale)) {
PhysicsServer3D::get_singleton()->end_sync();
PhysicsServer2D::get_singleton()->end_sync();
exit = true;
break;
}
uint64_t navigation_begin = OS::get_singleton()->get_ticks_usec();
NavigationServer3D::get_singleton()->process(physics_step * time_scale);
navigation_process_ticks = MAX(navigation_process_ticks, OS::get_singleton()->get_ticks_usec() - navigation_begin); // keep the largest one for reference
navigation_process_max = MAX(OS::get_singleton()->get_ticks_usec() - navigation_begin, navigation_process_max);
message_queue->flush();
PhysicsServer3D::get_singleton()->end_sync();
PhysicsServer3D::get_singleton()->step(physics_step * time_scale);
PhysicsServer2D::get_singleton()->end_sync();
PhysicsServer2D::get_singleton()->step(physics_step * time_scale);
message_queue->flush();
physics_process_ticks = MAX(physics_process_ticks, OS::get_singleton()->get_ticks_usec() - physics_begin); // keep the largest one for reference
physics_process_max = MAX(OS::get_singleton()->get_ticks_usec() - physics_begin, physics_process_max);
Engine::get_singleton()->_physics_frames++;
Engine::get_singleton()->_in_physics = false;
}
输入处理
if (Input::get_singleton()->is_using_input_buffering() && agile_input_event_flushing) {
Input::get_singleton()->flush_buffered_events();
}
uint64_t process_begin = OS::get_singleton()->get_ticks_usec();
if (OS::get_singleton()->get_main_loop()->process(process_step * time_scale)) {
exit = true;
}
message_queue->flush();
显示处理
RenderingServer::get_singleton()->sync(); //sync if still drawing from previous frames.
if (DisplayServer::get_singleton()->can_any_window_draw() &&
RenderingServer::get_singleton()->is_render_loop_enabled()) {
if ((!force_redraw_requested) && OS::get_singleton()->is_in_low_processor_usage_mode()) {
if (RenderingServer::get_singleton()->has_changed()) {
RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands
Engine::get_singleton()->frames_drawn++;
}
} else {
RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands
Engine::get_singleton()->frames_drawn++;
force_redraw_requested = false;
}
}
脚本处理
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptServer::get_language(i)->frame();
}
音频处理
AudioServer::get_singleton()->update();