Главная » Разработка для Windows Phone 7 » Захоронение и параметры для приложений на XNA

0

Как правило, приложения на XNA не строятся вокруг страниц, как приложения на Silverlight. Однако если это требуется, безусловно, в рамках приложения на XNA тоже можно

реализовать собственную страничную структуру. Вспомним, что состояние кнопки телефона Back проверяется при каждом вызове стандартного метода Update. Эта логика может использоваться в целях навигации, а также для завершения приложения. Но эту задачу я оставляю для самостоятельной проработки.

Приложение на XNA может использовать тот же класс PhoneApplicationService, с которым работали приложения на Silverlight, для хранения промежуточных данных состояния во время захоронения. Также этот класс может применяться приложением на XNA для установки обработчиков четырех событий PhoneApplicationService: Launching, Activated, Deactivated и Closing. Для этого понадобиться указать ссылки и на библиотеку Microsoft.Phone (для самого PhoneApplicationService), и на System.Windows (для интерфейса IApplicationService, реализуемого PhoneApplicationService). В файле Game1.cs необходимо подключить пространство имен Microsoft.Phone.Shell посредством директивы using.

В конструкторе класса Game1 с помощью статического свойства

PhoneApplicationService.Current можно получить ассоциированный с приложением экземпляр PhoneApplicationService.

Также класс Game описывает пару удобных и полезных для обработки захоронения виртуальных методов: OnActivated (При активации) и OnDeactivated (При деактивации). Метод OnActivated вызывается при запуске и повторной активации, метод OnDeactivated вызывается при деактивации и завершении приложения, во многом аналогично виртуальным методам OnNavigatedTo и OnNavigatedFrom страницы на Silverlight.

В приложении XnaTombstoning, которое завершает данную главу, я попытался повторить функциональность и структуру приложения SilverlightIsolatedStorage. XnaTombstoning использует события PhoneApplicationService для сохранения и восстановления параметров приложения (Color) и переопределяет события OnDeactivated и OnActivated для сохранения промежуточных данных (количества касаний).

Но я пошел несколько дальше и реализовал более обобщенное решение для параметров приложения. Для проекта XnaTombstoning был создан выделенный класс Settings, использующий обобщенные возможности изолированного хранилища, которые обеспечивают работу с реальными файлами, а не просто с параметрами. Нам понадобится ссылка на библиотеку System.Xml.Serialization для этого класса, а также директивы using для пространств имен System.IO, System.IO.IsolatedStorage и System.Xml.Serialization.

Проект Silverlight: XnaTombstoning Файл: Settings.cs (фрагмент)

public class Settings {

const string filename = "settings.xml"; // Параметры приложения

public Color BackgroundColor { set; get; }

public Settings() {

BackgroundColor = Color.Navy;

}

public void Save() {

IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication(); IsolatedStorageFileStream stream = storage.CreateFile(filename); XmlSerializer xml = new XmlSerializer(GetType()); xml.Serialize(stream, this); stream.Close();

stream.Dispose();

public static Settings Load() {

IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication(); Settings settings;

if (storage.FileExists(filename)) {

IsolatedStorageFileStream stream =

storage.OpenFile("settings.xml", FileMode.Open); XmlSerializer xml = new XmlSerializer(typeof(Settings)); settings = xml.Deserialize(stream) as Settings; stream.Close(); stream.Dispose();

}

else {

settings = new Settings();

}

return settings;

}

}

Основная идея здесь в том, что в ходе выполнения метода Save в изолированном хранилище сериализуется и сохраняется сам экземпляр класса Settings. Затем в методе Load выполняется его извлечение и десериализация. Обратите внимание, что метод Load статический и возвращает экземпляр класса Settings.

При сериализации класса Settings сериализуются все его открытые свойства. У этого класса всего одно открытое свойство BackgroundColor типа Color, но не составит никакого труда добавить в него больше свойств в ходе доработки и усложнения приложения.

В методе Save посредством статического метода IsolatedStorageFile.GetUserStoreForApplication получаем область изолированного хранилища, которая зарезервирована для данного приложения. Этот метод возвращает объект типа IsolatedStorageFile (Файл изолированного хранилища), но имя несколько не соответствует сути. Функциональность объекта IsolatedStorageFile больше соответствует файловой системе, а не файлу. Этот объект используется для хранения каталогов, создания и открытия файлов. Вызов CreateFile (Создать файл) возвращает IsolatedStorageFileStream (Файловый поток изолированного хранилища), который в данном примере используется с объектом XmlSerializer (Модуль сериализации XML) для сериализации и сохранения файла.

Метод Load несколько сложнее, поскольку существует вероятность того, что приложение выполняется впервые и файл settings.xml не существует. В этом случае Load создает новый экземпляр Settings.

Обратите внимание на конструктор, который инициализирует свойства значениями по умолчанию. В данном случае это касается только открытого свойства BackgroundColor. Если в какой-то момент добавить второе открытое свойство для другого параметра приложения, в конструкторе необходимо будет задать для него значение по умолчанию. Это новое свойство будет инициализировано в конструкторе при первом выполнении новой версии приложения, но метод Load извлечет файл, не имеющий этого свойства, таким образом, новая версия плавно интегрируется с предыдущей.

Еще одно замечание: данная схема подходит, только если свойства, представляющие параметры приложения, являются сериализуемыми. В более сложном приложении это условие может не выполняться. Для несериализуемых объектов, которые, тем не менее, должны быть сохранены в изолированное хранилище, в этот файл можно включить свойство, но его описание необходимо обозначить атрибутом [XmlIgnore]. Благодаря этому данное свойство будет игнорироваться при сериализации, но для его обработки в методах Save и Load придется предусмотреть специальный код.

Остальной код проекта XnaTombstoning обрабатывает функциональность касания экрана и ответ на них в виде изменения цвета фона случайным образом, а также подсчет количества касаний. Цвет фона рассматривается как параметр приложения (что очевидно из его включения в класс Settings), и количество касаний является промежуточным параметром.

Рассмотрим фрагмент класса Game1, включающий поля, конструктор и события PhoneApplicationService:

Проект Silverlight: XnaTombstoning Файл: Game1.cs (фрагмент)

public class Game1 : Microsoft.Xna.Framework.Game {

GraphicsDeviceManager graphics; SpriteBatch spriteBatch;

Settings settings;

SpriteFont segoe14;

Viewport viewport;

Random rand = new Random();

StringBuilder text = new StringBuilder();

Vector2 position;

int numTaps = 0;

public Game1() {

graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content";

// Частота кадров по умолчанию для Windows Phone составляет 30 кадр/с. TargetElapsedTime = TimeSpan.FromTicks(333333);

TouchPanel.EnabledGestures = GestureType.Tap;

PhoneApplicationService appService = PhoneApplicationService.Current; appService.Launching += OnAppServiceLaunching; appService.Activated += OnAppServiceActivated; appService.Deactivated += OnAppServiceDeactivated; appService.Closing += OnAppServiceClosing;

}

void OnAppServiceLaunching(object sender, LaunchingEventArgs args) settings = Settings.Load();

void OnAppServiceActivated(object sender, ActivatedEventArgs args) settings = Settings.Load();

void OnAppServiceDeactivated(object sender, DeactivatedEventArgs args) settings.Save();

void OnAppServiceClosing(object sender, ClosingEventArgs args) settings.Save();

}

}

Объект Settings под именем settings сохраняется как поле. Конструктор подключает обработчики для четырех событий класса PhoneApplicationService, и параметры приложения сохраняются и загружаются именно в обработчиках этих событий.

Перегруженный метод LoadContent не несет в себе никаких сюрпризов: Проект Silverlight: XnaTombstoning Файл: Game1.cs (фрагмент)

protected override void LoadContent() {

spriteBatch = new SpriteBatch(GraphicsDevice); segoe14 = this.Content.Load<SpriteFont>("Segoe14"); viewport = this.GraphicsDevice.Viewport;

}

Метод Update фиксирует касания, обновляет поле numTaps (Количество касаний), производит выбор нового цвета случайным образом и также подготавливает объект StringBuilder к отображению числа касаний:

Проект Silverlight: XnaTombstoning Файл: Game1.cs (фрагмент)

protected override void Update(GameTime gameTime) {

// Обеспечиваем выход из игры

if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit();

while (TouchPanel.IsGestureAvailable)

if (TouchPanel.ReadGesture().GestureType == GestureType.Tap) {

numTaps++;

settings.BackgroundColor = new Color((byte)rand.Next(255),

(byte)rand.Next(255), (byte)rand.Next(255));

}

text.Remove(0, text.Length);

text.AppendFormat("{0} taps total", numTaps);

Vector2 textSize = segoe14.MeasureString(text.ToString());

position = new Vector2((viewport.Width – textSize.X) / 2,

(viewport.Height – textSize.Y) / 2);

base.Update(gameTime);

}

Обратите внимание, что новый цвет сохраняется не как поле, а как свойство BackgroundColor экземпляра Settings. Затем это свойство используется в перегруженном методе Draw:

Проект Silverlight: XnaTombstoning Файл: Game1.cs (фрагмент)

protected override void Draw(GameTime gameTime) {

GraphicsDevice.Clear(settings.BackgroundColor); spriteBatch.Begin();

spriteBatch.DrawString(segoe14, text, position, Color.White); spriteBatch.End();

base.Draw(gameTime);

}

Промежуточное значение поля numTaps сохраняется и восстанавливается из словаря State объекта PhoneApplicationService в перегруженных методах OnActivated и OnDeactivated:

Проект Silverlight: XnaTombstoning Файл: Game1.cs (фрагмент)

protected override void OnActivated(object sender, EventArgs args) {

if (PhoneApplicationService.Current.State.ContainsKey("numTaps"))

numTaps = (int)PhoneApplicationService.Current.State["numTaps"];

base.OnActivated(sender, args);

}

protected override void OnDeactivated(object sender, EventArgs args) {

PhoneApplicationService.Current.State["numTaps"] = numTaps; base.OnDeactivated(sender, args);

}

Решение сохранять и восстанавливать параметры приложения в одном наборе обработчиков событий, а промежуточные параметры – в другом наборе перегруженных виртуальных методов, довольно произвольно. Метод OnActivated будет вызываться в приложении практически одновременно с формированием событий Launching и Activated; и метод OnDeactivated – одновременно с формированием событий Deactivated и Closing. Более концептуальное различие в том, что OnActivated и OnDeactivated ассоциированы с экземпляром Game, поэтому должны использоваться для свойств, связанных с игрой, а не для параметров приложения в целом.

Возможно, возникнет необходимость сохранять как промежуточный параметр несериализуемый объект. Однако поскольку он не является сериализуемым, для его хранения не может использоваться словарь State класса PhoneApplicationService, а понадобится изолированное хранилище. При этом необходимо гарантированно обеспечить, что этот объект не будет случайно извлечен и повторно использован при очередном выполнении приложения. На этот случай в словаре State предусмотрен флаг, указывающий на необходимость загрузки промежуточного объекта из изолированного хранилища.

Тестирование и эксперименты

Разработчики Майкрософт, которые занимаются созданием приложений для Windows Phone 7 намного дольше, чем многие из нас, говорят, что реализация захоронения является, пожалуй, одним из самых сложных аспектов разработки для телефона. Представленные мною в данной главе методики хороши как исходные приемы, но требования всех приложений немного отличаются. Несомненно, желательно реализовывать максимальный объем тестирования в собственных приложениях, всегда полезно точно знать, какие методы приложения и в каком порядке вызываются. Для этого очень пригодится метод Debug.WriteLine из пространства имен System.Diagnostics.

Источник: Чарльз Петзольд, Программируем Windows Phone 7, Microsoft Press, © 2011.

По теме:

  • Комментарии