日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

UE4启动GameActivity

發(fā)布時間:2023/12/9 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UE4启动GameActivity 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

UE Android項目工程中的GameActivity基于NativeActivity,相關(guān)知識請參考之前的一篇文章,NativeActivity介紹
在之前NativeActivity介紹中,我們知道膠水層app_native_app_glue會創(chuàng)建一個子線程并prepare()開啟loop循環(huán)。UE中這個線程又叫做GameThread,用于處理游戲邏輯業(yè)務(wù)。初次之外,通過android_main()入口,在UE4引擎代碼LaunchAndroid中會創(chuàng)建一個AndroidProcessEvents,用來輪詢并處理cmd命令和input事件。

android_main()

void android_main(struct android_app* state) { //STEP1 獲取當(dāng)前GameThread線程Id,并將android_app賦值給到GNativeAndroidAppGGameThreadId = FPlatformTLS::GetCurrentThreadId();BootTimingPoint("android_main");FPlatformMisc::LowLevelOutputDebugString(TEXT("Entering native app glue main function"));GNativeAndroidApp = state;check(GNativeAndroidApp); //STEP2 創(chuàng)建新的AndroidEventThreadWorker線程,用來處理cmd和input事件。 //關(guān)于這兩類事件,可以參考源碼文檔中 //https://cs.android.com/android/platform/superproject/+/master:prebuilts/ndk/current/sources/android/native_app_glue/android_native_app_glue.h 對android_app數(shù)據(jù)結(jié)構(gòu)的注解pthread_attr_t otherAttr; pthread_attr_init(&otherAttr);pthread_attr_setdetachstate(&otherAttr, PTHREAD_CREATE_DETACHED);pthread_create(&G_AndroidEventThread, &otherAttr, AndroidEventThreadWorker, state);FPlatformMisc::LowLevelOutputDebugString(TEXT("Created event thread"));// Make sure glue isn't stripped. (not needed in ndk-15) #if PLATFORM_ANDROID_NDK_VERSION < 150000app_dummy(); #endif //STEP3 進入到GameThread的主循環(huán),里面會初始化ue引擎以及定時tick//@todo android: replace with native activity, main loop off of UI thread, etc.AndroidMain(state); }

android_main做了三件事情

  • 獲取當(dāng)前GameThread Id,將android_app賦值給到GNativeAndroidApp,struct android_app 定義
  • 創(chuàng)建AndroidEventThreadWorker線程,處理cmd和input事件
  • 調(diào)用AndroidMain函數(shù)
  • AndroidMain()

    //Main function called from the android entry point int32 AndroidMain(struct android_app* state) {BootTimingPoint("AndroidMain");FPlatformMisc::LowLevelOutputDebugString(TEXT("Entered AndroidMain()\n"));// Force the first call to GetJavaEnv() to happen on the game thread, allowing subsequent calls to occur on any threadFAndroidApplication::GetJavaEnv();// Set window format to 8888ANativeActivity_setWindowFormat(state->activity, WINDOW_FORMAT_RGBA_8888);//balabala...//阻塞等待ResumeMainInit被調(diào)用// wait for java activity onCreate to finish{SCOPED_BOOT_TIMING("Wait for GResumeMainInit");while (!GResumeMainInit){FPlatformProcess::Sleep(0.01f);FPlatformMisc::MemoryBarrier();}}// read the command line fileInitCommandLine();// ready for onCreate to completeGEventHandlerInitialized = true;// 初始化文件掛載// Initialize file system access (i.e. mount OBBs, etc.).// We need to do this really early for Android so that files in the// OBBs and APK are found.IPlatformFile::GetPlatformPhysical().Initialize(nullptr, FCommandLine::Get());// balabala...// pre初始化游戲引擎// initialize the engine int32 PreInitResult = GEngineLoop.PreInit(0, NULL, FCommandLine::Get());// 若pre初始化失敗直接退出游戲線程if (PreInitResult != 0){checkf(false, TEXT("Engine Preinit Failed"));return PreInitResult;}// balabala...// 初始化游戲引擎GEngineLoop.Init();bDidCompleteEngineInit = true;UE_LOG(LogAndroid, Log, TEXT("Passed GEngineLoop.Init()"));// balabala...//開始TICK// tick until donewhile (!IsEngineExitRequested()){FAndroidStats::UpdateAndroidStats();FAppEventManager::GetInstance()->Tick();if(!FAppEventManager::GetInstance()->IsGamePaused()){GEngineLoop.Tick();}else{// use less CPU when pausedFPlatformProcess::Sleep(0.10f);}//balabala...}//退出游戲則走到這里來FAppEventManager::GetInstance()->TriggerEmptyQueue();UE_LOG(LogAndroid, Log, TEXT("Exiting"));// exit out!GEngineLoop.Exit();UE_LOG(LogAndroid, Log, TEXT("Exiting is over"));FPlatformMisc::RequestExit(1);return 0; }

    AndroidMain中做了這么幾件事情

  • 阻塞等待ResumeMainInit被調(diào)用
  • 初始化文件系統(tǒng)權(quán)限
  • 初始化游戲引擎,失敗直接結(jié)束線程
  • tick循環(huán),TICK中處理游戲邏輯
  • 退出游戲線程
  • Activity生命周期處理和input輸入事件處理

    通過NativeActivity一文,我們梳理了cmd和input事件的處理流程


    而在UE項目中,在AndroidEventThreadWorker中實現(xiàn)了onAppCmd()和onInputEvent()方法,用來響應(yīng)cmd和input事件

    static void* AndroidEventThreadWorker( void* param ) {FAndroidMisc::SetThreadName("EventWorker");struct android_app* state = (struct android_app*)param;FPlatformProcess::SetThreadAffinityMask(FPlatformAffinity::GetMainGameMask());FPlatformMisc::LowLevelOutputDebugString(TEXT("Entering event processing thread engine entry point"));EventThreadID = FPlatformTLS::GetCurrentThreadId();ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);ALooper_addFd(looper, state->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,&state->cmdPollSource);state->looper = looper;FPlatformMisc::LowLevelOutputDebugString(TEXT("Prepared looper for event thread"));//callback賦值,膠水層的事件響應(yīng)最終會調(diào)用這里的方法//Assign the callbacksstate->onAppCmd = OnAppCommandCB;state->onInputEvent = HandleInputCB;FPlatformMisc::LowLevelOutputDebugString(TEXT("Passed callback initialization"));FPlatformMisc::LowLevelOutputDebugString(TEXT("Passed sensor initialization"));TheChoreographer.SetupChoreographer();// window is initially invalid/locked.UE_LOG(LogAndroid, Log, TEXT("event thread, Initial HW window lock."));GAndroidWindowLock.Lock();//continue to process events until the engine is shutting downwhile (!IsEngineExitRequested()){ // FPlatformMisc::LowLevelOutputDebugString(TEXT("AndroidEventThreadWorker"));//這里有點不明白,NativeActivity中已經(jīng)處理了事件,這里的是用來干啥的AndroidProcessEvents(state);sleep(EventRefreshRate); // this is really 0 since it takes int seconds.}GAndroidWindowLock.Unlock();UE_LOG(LogAndroid, Log, TEXT("Exiting"));return NULL; }

    OnAppCommandCB方法中會處理事件,并且將有關(guān)的事件推到UE自身的queue(GameThread中)中,并且在下一次tick到來的時候消費掉

    //Called from the event process thread static void OnAppCommandCB(struct android_app* app, int32_t cmd) {check(IsInAndroidEventThread());static bool bDidGainFocus = false;//FPlatformMisc::LowLevelOutputDebugStringf(TEXT("OnAppCommandCB cmd: %u, tid = %d"), cmd, gettid());static bool bHasFocus = false;static bool bHasWindow = false;static bool bIsResumed = false;// Set event thread's view of the window dimensions:{ANativeWindow* DimensionWindow = app->pendingWindow ? app->pendingWindow : app->window;if (DimensionWindow){FAndroidWindow::SetWindowDimensions_EventThread(DimensionWindow);}}switch (cmd){case APP_CMD_SAVE_STATE:/*** Command from main thread: the app should generate a new saved state* for itself, to restore from later if needed. If you have saved state,* allocate it with malloc and place it in android_app.savedState with* the size in android_app.savedStateSize. The will be freed for you* later.*/// the OS asked us to save the state of the appUE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_SAVE_STATE"));//推送到UE的QUEUE中,最終在tick()執(zhí)行的時候消費掉FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_SAVE_STATE);break;//balabala....}//balabala... }

    在AndroidEventManager.cpp中實現(xiàn)了Tick()

    void FAppEventManager::Tick() {check(IsInGameThread());while (!Queue.IsEmpty()){FAppEventPacket Event = DequeueAppEvent();FPlatformMisc::LowLevelOutputDebugStringf(TEXT("FAppEventManager::Tick processing, %d"), int(Event.State));switch (Event.State){case APP_EVENT_STATE_WINDOW_CREATED:FAndroidWindow::EventManagerUpdateWindowDimensions(Event.Data.WindowWidth, Event.Data.WindowHeight);bCreateWindow = true;break;case APP_EVENT_STATE_WINDOW_RESIZED:// Cache the new window's dimensions for the game thread.FAndroidWindow::EventManagerUpdateWindowDimensions(Event.Data.WindowWidth, Event.Data.WindowHeight);ExecWindowResized();break;case APP_EVENT_STATE_WINDOW_CHANGED:// React on device orientation/windowSize changes only when application has window// In case window was created this tick it should already has correct size// see 'Java_com_epicgames_ue4_GameActivity_nativeOnConfigurationChanged' for event thread/game thread mismatches.ExecWindowResized();break;case APP_EVENT_STATE_SAVE_STATE:bSaveState = true; //todo android: handle save state.break;//balabala...}//balabala... }

    這里涉及到多個線程的通信,事件傳遞后續(xù)會以線程間傳遞的方式來介紹
    UIThread (Android sdk)
    GameThread (Android NDK創(chuàng)建,NDK和UE都使用)
    AndroidEventThread(UE創(chuàng)建并使用)

    總結(jié)

    以上是生活随笔為你收集整理的UE4启动GameActivity的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。