[[C++API/Launch.cpp]] 游戏循环:死循环,Launch.cpp ```cpp // Copyright Epic Games, Inc. All Rights Reserved. #include "CoreMinimal.h" #include "Misc/CommandLine.h" #include "Misc/App.h" #include "Misc/OutputDeviceError.h" #include "LaunchEngineLoop.h" #include "PhysicsPublic.h" #include "HAL/ExceptionHandling.h" #include "Modules/ModuleManager.h" #include "ProfilingDebugging/LoadTimeTracker.h" #include "Stats/StatsMisc.h" #include "Misc/CoreDelegates.h" #include "Misc/EngineVersion.h" #include "Misc/ScopedSlowTask.h" #if WITH_EDITOR #include "UnrealEdGlobals.h" #endif #if PLATFORM_WINDOWS #include "Windows/WindowsHWrapper.h" #endif IMPLEMENT_MODULE(FDefaultModuleImpl, Launch); #if PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_UNIX || PLATFORM_USE_GENERIC_LAUNCH_IMPLEMENTATION //引擎循环 FEngineLoop GEngineLoop; //控制台窗口 bool GIsConsoleExecutable = false; extern "C" int test_main(int argc, char ** argp) { return 0; } /** * PreInits the engine loop * 引擎预加载 */ int32 EnginePreInit( const TCHAR* CmdLine ) { int32 ErrorLevel = GEngineLoop.PreInit( CmdLine ); return( ErrorLevel ); } /** * Inits the engine loop * 初始化 */ int32 EngineInit() { int32 ErrorLevel = GEngineLoop.Init(); return( ErrorLevel ); } /** * Ticks the engine loop * 引擎执行每一帧的循环逻辑 */ void EngineTick( void ) { GEngineLoop.Tick(); } /** * Shuts down the engine * 引擎退出 * */ void EngineExit( void ) { // Make sure this is set RequestEngineExit(TEXT("EngineExit() was called")); GEngineLoop.Exit(); } /** * Performs any required cleanup in the case of a fatal error. */void LaunchStaticShutdownAfterError() { // Make sure physics is correctly torn down. TermGamePhys(); } #if WITH_EDITOR extern UNREALED_API FSecondsCounterData BlueprintCompileAndLoadTimerData; #endif /** * Static guarded main function. Rolled into own function so we can have error handling for debug/ release builds depending * on whether a debugger is attached or not. */int32 GuardedMain( const TCHAR* CmdLine ) { #if !(UE_BUILD_SHIPPING) if (FParse::Param(CmdLine, TEXT("waitforattach"))) { while (!FPlatformMisc::IsDebuggerPresent()); UE_DEBUG_BREAK(); }#endif BootTimingPoint("DefaultMain"); // Super early init code. DO NOT MOVE THIS ANYWHERE ELSE! FCoreDelegates::GetPreMainInitDelegate().Broadcast(); // make sure GEngineLoop::Exit() is always called. struct EngineLoopCleanupGuard { ~EngineLoopCleanupGuard() { EngineExit(); } } CleanupGuard; // Set up minidump filename. We cannot do this directly inside main as we use an FString that requires // destruction and main uses SEH. // These names will be updated as soon as the Filemanager is set up so we can write to the log file. // That will also use the user folder for installed builds so we don't write into program files or whatever.#if PLATFORM_WINDOWS FCString::Strcpy(MiniDumpFilenameW, *FString::Printf(TEXT("unreal-v%i-%s.dmp"), FEngineVersion::Current().GetChangelist(), *FDateTime::Now().ToString())); GIsConsoleExecutable = (GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) == FILE_TYPE_CHAR); #endif int32 ErrorLevel = EnginePreInit( CmdLine ); // exit if PreInit failed. if ( ErrorLevel != 0 || IsEngineExitRequested() ) { return ErrorLevel; } { FScopedSlowTask SlowTask(100, NSLOCTEXT("EngineInit", "EngineInit_Loading", "Loading...")); // EnginePreInit leaves 20% unused in its slow task. // Here we consume 80% immediately so that the percentage value on the splash screen doesn't change from one slow task to the next. // (Note, we can't include the call to EnginePreInit in this ScopedSlowTask, because the engine isn't fully initialized at that point) SlowTask.EnterProgressFrame(80); SlowTask.EnterProgressFrame(20); #if WITH_EDITOR if (GIsEditor) { ErrorLevel = EditorInit(GEngineLoop); } else #endif { ErrorLevel = EngineInit(); } } double EngineInitializationTime = FPlatformTime::Seconds() - GStartTime; UE_LOG(LogLoad, Log, TEXT("(Engine Initialization) Total time: %.2f seconds"), EngineInitializationTime); #if WITH_EDITOR UE_LOG(LogLoad, Log, TEXT("(Engine Initialization) Total Blueprint compile time: %.2f seconds"), BlueprintCompileAndLoadTimerData.GetTime()); #endif ACCUM_LOADTIME(TEXT("EngineInitialization"), EngineInitializationTime); BootTimingPoint("Tick loop starting"); DumpBootTiming(); while( !IsEngineExitRequested() ) { EngineTick(); } TRACE_BOOKMARK(TEXT("Tick loop end")); #if WITH_EDITOR if( GIsEditor ) { EditorExit(); }#endif return ErrorLevel; } #endif ``` 预初始化: + 在决定加载什么包,uplugin、uproject定义的包 + uproject本质是一个json文件,preinit就是解析json并加载json文件中定义的包 让虚幻引擎注册这些模块的类,初始化必须的底层系统。 + 需要让引擎启动起来,则需要一些底层的数据和类的支持 + 一般顺序是由引擎自身控制 + Core(数据类型 Log String Name 3DMath Delegates Layer ) + CoreUObject ([[C++API/反射系统|反射系统]],序列化,资源加载,[[垃圾回收]],BlueprintScript) + InputCore 输入key + Engine 引擎、动画、网格、材质、特性、音效、关卡、Actor、World、GameMode Controller、Component 等等 + UnrealED EditorApplication 编辑器 + StateCore、 Slate (空间蓝图的基础) UILayout Fonts images icons Input Stying BaseWidgetType LoadCoreModules LoadPreInitModules LoadStartUpCoreModules 先加载底层一些模块,底层的关键系统在此初始化和类型定义。 自定义的项目和插件的模块,有需要被提前加载的被加载。 接着一些更高级的关键系统,项目和插件加载。 最后一步才是自定义代码的加载。 ```cpp /** * PreInits the engine loop */ int32 EnginePreInit( const TCHAR* CmdLine ) { int32 ErrorLevel = GEngineLoop.PreInit( CmdLine ); return( ErrorLevel ); } ``` FModuleManager加载包(模块)管理者、单例类 游戏实例的初始化,在游戏引擎初始化时,便初始化了。 FEngineLoop:Init UGameEngine:Start UGameInstance:StartGameInstance UEngine:BrowseDefaultMap UEngine:LoadMap UGameEngine 游戏引擎类,被初始化和启动 UGameInstance 被初始化和启动 UGameViewPortClient 游戏视口被创建 ULocalPlayer 表达全局唯一的玩家的概念被创建 EngineObject --- LoadMap --- GameObject UWorld Ulevel AActor UActorComponent AGameMode AGameSession AGameState AGameNetWork APlayerController APlayerState # UE底层运行逻辑 LanchEngineLoop 提供了对引擎进行预初始化,初始化,更新和退出的调用机制。 Launch.cpp 是引擎的程序入口也就是Main 定义了EngineLoop 的全局变量,并调用响应的函数。 预初始化 是完成对引擎底层模块 插件模块和自定义模块的加载 初始化 实例化了GameEngine的全局变量,并定义了GameInstance ViewPort LocalPlayer GameEngine在完成了变量的创建Init之后,会执行Start 帮助我们LoadMap LoadMap创建了UWorld,UWorld才是GamePlay游戏开发框架的基础机制。 # GamePlay框架 World 和 Map 意义相同,可以互换,都表示一张地图或者一个世界。 而世界中,有多个Level或者一个Level组成 Level中可以不包含Actor 也可以包含多个Actor。 持久关卡会默认和World一起被加载,流送关卡在不同时间段显示或隐藏。 FWorldContext UWorld UGameInstance 三者可以相互获取,相互依存。 World会完成对游戏内的初始化工作。 加载Level 加载Level中的Actor 并给Actor 添加各个Component组件 AGameSession 会话类 处理登录连接请求,在线服务相关 AGameNetWorkManager 网络管理类 AGameMode 游戏规则类 AGameStateBase 游戏状态类 ULocalPlayer 和 PlayerController ULocalPlayer是引擎里玩家的代表,再UEngine::init里创建 PlayerController是玩家在地图里的代表。 LocalPlayer是玩家的抽象化,PlayerController是玩家的具体化。 NetConnection 网络连接对象,表示一个远程的Player [[UObject]] ![[Picture/UE.png]]