You could call the AppCallbacks class a bridge between your main application and the Unity engine. Here, we’ll try to explain what every call to AppCallbacks exactly does. Let’s build solution and explore App.xaml.cpp and MainPage.xaml.cpp files.
App::App()
{
InitializeComponent();
SetupOrientation();
m_AppCallbacks = ref new AppCallbacks();
}
void App::OnLaunched(LaunchActivatedEventArgs^ e)
{
m_SplashScreen = e->SplashScreen;
InitializeUnity(e->Arguments);
}
void App::InitializeUnity(String^ args)
{
ApplicationView::GetForCurrentView()->SuppressSystemOverlays = true;
m_AppCallbacks->SetAppArguments(args);
auto rootFrame = safe_cast<Frame^>(Window::Current->Content);
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr && !m_AppCallbacks->IsInitialized())
{
rootFrame = ref new Frame();
Window::Current->Content = rootFrame;
#if !UNITY_HOLOGRAPHIC
Window::Current->Activate();
#endif
rootFrame->Navigate(TypeName(MainPage::typeid ));
}
Window::Current->Activate();
}
MainPage::MainPage()
{
m_SplashScreenRemovalEventToken.Value = 0;
m_OnResizeRegistrationToken.Value = 0;
InitializeComponent();
NavigationCacheMode = ::NavigationCacheMode::Required;
auto appCallbacks = AppCallbacks::Instance;
bool isWindowsHolographic = false;
#if UNITY_HOLOGRAPHIC
// If application was exported as Holographic check if the device actually supports it,
// otherwise we treat this as a normal XAML application
isWindowsHolographic = AppCallbacks::IsMixedRealitySupported();
#endif
if (isWindowsHolographic)
{
appCallbacks->InitializeViewManager(Window::Current->CoreWindow);
}
else
{
m_SplashScreenRemovalEventToken = appCallbacks->RenderingStarted += ref new RenderingStartedHandler(this, &MainPage::RemoveSplashScreen);
appCallbacks->SetSwapChainPanel(m_DXSwapChainPanel);
appCallbacks->SetCoreWindowEvents(Window::Current->CoreWindow);
appCallbacks->InitializeD3DXAML();
m_SplashScreen = safe_cast<App^>(App::Current)->GetSplashScreen();
auto dispatcher = CoreWindow::GetForCurrentThread()->Dispatcher;
ThreadPool::RunAsync(ref new WorkItemHandler([this, dispatcher](IAsyncAction^)
{
GetSplashBackgroundColor(dispatcher);
}));
OnResize();
m_OnResizeRegistrationToken = Window::Current->SizeChanged += ref new WindowSizeChangedEventHandler([this](Object^, WindowSizeChangedEventArgs^)
{
OnResize();
});
}
}
m_AppCallbacks = ref new AppCallbacks();
Let’s take a closer look at AppCallbacks class. When you create it, Unity creates a new thread called “AppThread”. This is done because there’s a restriction from Microsoft - if your application does not become responsive after 5 seconds you’ll fail to pass WACK (Windows Application Certification). (You can read more here - http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh184840(v=vs.105).aspx) Imagine if your first level is pretty big and takes a significant amount of time to load. Because your application is running on UI thread, the UI will be unresponsive until your level is fully loaded. That’s why Unity always runs your game on different thread.
Read more on the UI thread here - http://msdn.microsoft.com/en-us/library/windows/apps/hh994635.aspx
You can also pass custom command line arguments as string array into the AppCallbacks constructor.
Note: Code located in App.xaml.cpp, MainPage.xaml.c[[ is always running on UI thread, unless called from InvokeOnAppThread function.
appCallbacks->SetSwapChainPanel(m_DXSwapChainPanel);
このシンプルな XAML コントロールから Unity へのパスは DirectX 11 での対象の描画に使用されます。
appCallbacks->SetCoreWindowEvents(Window::Current->CoreWindow);
Unity に CoreWindow を設定すると Unity は次のイベントを扱えるようになります (最新のものではさらに増えている可能性があります)
appCallbacks->InitializeD3DXAML();
これは Unity のためのメイン初期化関数で、次のことを行います。
このとき Unity が最初のゲームステージの読み込みを完了した時点で、メインループを開始します。
Invokes a delegate on application thread, which is useful when you want to execute your script function from UI thread.
デリゲートの実行を UI スレッドへ依頼します。何かしらの XAML 固有 API をスクリプトから実行の依頼をしたい場合に使用します。
アプリケーションスレッドで実行されている場合は true を返します。
UI スレッドで実行されている場合は true を返します。
D3D アプリケーションを初期化する関数です。
D3D アプリケーションのメインループを開始するための関数です。
最初のゲームステージが完全に読み込まれていると true を返します。
アプリケーションのためにコマンドライン引数を設定します。InitializeD3DWindow()、InitializeD3DXAML() の前に呼ばれる必要があります。
Unity API から後でアクセスするためのアプリケーション引数を設定します - UnityEngine.WSA.Application.arguments
この関数は、非推奨で動作しません。Unity の旧バージョンでは、UnityRenderEvent などでコールバックのネイティブプラグインを登録する必要がありました。現在は、すべてのプラグインが自動的に登録されます。この関数は今後のアップデートで削除されます。
コマンドライン引数をファイルから解析します。引数はスペースで区切られている必要があります。
1 を渡すと Unity は一時停止し、0 を渡すと解除します。ゲームを一時的に停止させたい場合に使用します。例えばゲームのキャプチャを撮った場合などです。
入力の可否を切り替えます。
Unity が入力を処理できる場合 ture を返します。
スクリーンキーボードのトリガに使うコントロールを設定します。このコントロールはスクリプトからスクリーンキーボードが要求されるとシンプルなフォーカスを受け取ります。コントロールが呼ばれるとフォーカスされたキーボードをオープンします。
キーボード入力のトリガとして使っているコントロールを返します。SetKeyboardTriggerControl を参照してください。
CoreWindow と独立した入力ソース (使用している場合) の両方にシステムカーソルを当てます。
CoreWindow と独立した入力ソース (使用している場合) の両方にカスタムのカーソルを当てます。パラメータにはカーソルのリソース ID を指定します。