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 的核心窗口,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 将处理传入的输入,返回 true。
设置用于触发屏幕键盘的控件。在脚本中请求屏幕键盘时,此控件将直接获得焦点。应该用控件进行调用,这样会打开处于焦点状态的键盘。
返回控件,即当前用于触发键盘输入的控件。请参阅 SetKeyboardTriggerControl。
设置系统光标。为 CoreWindow 和独立输入源(如果使用)设置给定光标。
将系统光标设置为自定义设置。参数为光标资源 ID。为 CoreWindow 和独立输入源(如果使用)设置光标。