Невозможно пройти тесты, в окне с вопросами пусто |
Совместное использование Silverlight и XNA
Цель работы: Научиться разрабатывать приложения с использованием шаблона Приложение Silverlight и XNA для Windows Phone
35.1. Особенности проекта Приложение Silverlight и XNA для Windows Phone
В некоторых из предыдущих проектов мы использовали отдельные библиотеки и объекты XNA в Silverlight-приложениях. Начиная с Windows Phone OS 7.1. при разработке приложений можно в полной мере пользоваться возможностями Silverlight и XNA в одном приложении. Например, можно создать сложный пользовательский интерфейс на Silverlight, и, в то же время, организовать вывод графики с помощью средств XNA. Фактически, такое приложение позволяет взять всё лучшее от обеих технологий.
Рассмотрим особенности таких приложений. Создадим новый проект, в окне создания проекта выберем шаблон Приложение Silverlight и XNA для Windows Phone, рис. 35.1.
Посмотрим на Обозреватель решений этого проекта, рис. 35.2
Если рассмотреть это решение в первом приближении, то окажется, что мы имеем Silverlight-проект, в котором есть механизмы для визуализации средствами XNA и страница GamePage.xaml, код которой (GamePage.xaml.cs) представляет собой реализацию игрового цикла XNA. Весь вывод данных на этой странице формируется средствами XNA.
Рассмотрим решение подробнее. Оно состоит из трёх проектов:
- Основной проект приложения (P28_1). Это проект приложения, здесь содержатся страницы приложения. Причём, страница MainPage – это обычная Silverlight-страница, которая отображается после запуска приложения, на ней, по умолчанию, расположена кнопка для вызова страницы GamePage.
- Проект библиотеки XNA (P28_1Lib). Этот проект напоминает проект XNA, разработкой которых мы занимались ранее в этом курсе. Он имеет ссылку на проект контента. Этот проект представляет собой нечто вроде моста между Silverlight-приложением и хранилищем контента.
- Проект контента XNA (P281Lib_Content). Традиционный для XNA-приложений проект, содержащий контент – изображения, звуки, трехмерные модели.
Рассмотрим файлы, которые входят в решение. Начнём с файла App.xaml, листинге 35.1.
<Application x:Class="P28_1.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:xna="clr-namespace:Microsoft.Xna.Framework;assembly=Microsoft.Xna.Framework.Interop"> <!--Ресурсы приложения--> <Application.Resources> </Application.Resources> <Application.ApplicationLifetimeObjects> <!--Обязательный объект, обрабатывающий события времени жизни приложения--> <shell:PhoneApplicationService Launching="Application_Launching" Closing="Application_Closing" Activated="Application_Activated" Deactivated="Application_Deactivated"/> <!--SharedGraphicsDeviceManager используется для отображения с помощью графических API XNA--> <xna:SharedGraphicsDeviceManager /> </Application.ApplicationLifetimeObjects> </Application>Листинг 35.1. Файл App.xaml
Этот файл, как и в случае с обычным Silverlight-приложением, определяет обработчики события, касающиеся жизненного цикла приложения, и, кроме того, определяет xna:SharedGraphicsDeviceManager – объект, который используется для вывода XNA-графики.
В листинге 35.2 приведен файл App.xaml.cs,
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Navigation; using System.Windows.Shapes; using Microsoft.Phone.Controls; using Microsoft.Phone.Shell; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; namespace P28_1 { public partial class App : Application { /// <summary> /// Обеспечивает быстрый доступ к корневому кадру приложения телефона. /// </summary> /// <returns>Корневой кадр приложения телефона.</returns> public PhoneApplicationFrame RootFrame { get; private set; } /// <summary> /// Предоставляет приложению доступ к ContentManager. /// </summary> public ContentManager Content { get; private set; } /// <summary> /// Предоставляет доступ к GameTimer, настроенному для передачи данных в FrameworkDispatcher. /// </summary> public GameTimer FrameworkDispatcherTimer { get; private set; } /// <summary> /// Предоставляет доступ к AppServiceProvider для приложения. /// </summary> public AppServiceProvider Services { get; private set; } /// <summary> /// Конструктор объекта приложения. /// </summary> public App() { // Глобальный обработчик неперехваченных исключений. UnhandledException += Application_UnhandledException; // Стандартная инициализация Silverlight InitializeComponent(); // Инициализация телефона InitializePhoneApplication(); // Инициализация XNA InitializeXnaApplication(); // Отображение сведений о профиле графики во время отладки. if (System.Diagnostics.Debugger.IsAttached) { // Отображение текущих счетчиков частоты смены кадров. Application.Current.Host.Settings.EnableFrameRateCounter = true; // Отображение областей приложения, перерисовываемых в каждом кадре. //Application.Current.Host.Settings.EnableRedrawRegions = true; // Включение режима визуализации анализа нерабочего кода // для отображения областей страницы, переданных в GPU, с цветным наложением. //Application.Current.Host.Settings.EnableCacheVisualization = true; // Отключите обнаружение простоя приложения, установив для свойства UserIdleDetectionMode // объекта PhoneApplicationService приложения значение Disabled. // Внимание! Используйте только в режиме отладки. Приложение, в котором отключено обнаружение бездействия пользователя, будет продолжать работать // и потреблять энергию батареи, когда телефон не будет использоваться. PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled; } } // Код для выполнения при запуске приложения (например, из меню "Пуск") // Этот код не будет выполняться при повторной активации приложения private void Application_Launching(object sender, LaunchingEventArgs e) { } // Код для выполнения при активации приложения (переводится в основной режим) // Этот код не будет выполняться при первом запуске приложения private void Application_Activated(object sender, ActivatedEventArgs e) { } // Код для выполнения при деактивации приложения (отправляется в фоновый режим) // Этот код не будет выполняться при закрытии приложения private void Application_Deactivated(object sender, DeactivatedEventArgs e) { } // Код для выполнения при закрытии приложения (например, при нажатии пользователем кнопки "Назад") // Этот код не будет выполняться при деактивации приложения private void Application_Closing(object sender, ClosingEventArgs e) { } // Код для выполнения в случае ошибки навигации private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e) { if (System.Diagnostics.Debugger.IsAttached) { // Ошибка навигации; перейти в отладчик System.Diagnostics.Debugger.Break(); } } // Код для выполнения на необработанных исключениях private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) { if (System.Diagnostics.Debugger.IsAttached) { // Произошло необработанное исключение; перейти в отладчик System.Diagnostics.Debugger.Break(); } } #region Инициализация приложения телефона // Избегайте двойной инициализации private bool phoneApplicationInitialized = false; // Не добавляйте в этот метод дополнительный код private void InitializePhoneApplication() { if (phoneApplicationInitialized) return; // Создайте кадр, но не задавайте для него значение RootVisual; это позволит // экрану-заставке оставаться активным, пока приложение не будет готово для визуализации. RootFrame = new PhoneApplicationFrame(); RootFrame.Navigated += CompleteInitializePhoneApplication; // Обработка сбоев навигации RootFrame.NavigationFailed += RootFrame_NavigationFailed; // Убедитесь, что инициализация не выполняется повторно phoneApplicationInitialized = true; } // Не добавляйте в этот метод дополнительный код private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e) { // Задайте корневой визуальный элемент для визуализации приложения if (RootVisual != RootFrame) RootVisual = RootFrame; // Удалите этот обработчик, т.к. он больше не нужен RootFrame.Navigated -= CompleteInitializePhoneApplication; } #endregion #region Инициализация приложения XNA // Выполняет инициализацию типов XNA, необходимых для приложения. private void InitializeXnaApplication() { // Создание поставщика услуг Services = new AppServiceProvider(); // Добавить SharedGraphicsDeviceManager к службам в качестве IGraphicsDeviceService для приложения foreach (object obj in ApplicationLifetimeObjects) { if (obj is IGraphicsDeviceService) Services.AddService(typeof(IGraphicsDeviceService), obj); } // Создайте ContentManager для загрузки в приложение предварительно скомпилированных ресурсов Content = new ContentManager(Services, "Content"); // Создайте GameTimer для получения XNA FrameworkDispatcher FrameworkDispatcherTimer = new GameTimer(); FrameworkDispatcherTimer.FrameAction += FrameworkDispatcherFrameAction; FrameworkDispatcherTimer.Start(); } // Обработчик событий передает FrameworkDispatcher во все кадры. // FrameworkDispatcher требуется для большинства событий XNA и // некоторых функций, таких как воспроизведение SoundEffect. private void FrameworkDispatcherFrameAction(object sender, EventArgs e) { FrameworkDispatcher.Update(); } #endregion } }Листинг 35.2. Файл App.xaml.cs
Это всё тот же App.xaml.cs, которым мы пользовались ранее, однако, здесь производится инициализация механизмов XNA, создается ConetntManager для работы с XNA-контентом, создаётся таймер уровня приложения для FrameworkDispatcher.Update().