Цель работы: Научиться сохранять и загружать состояния игр, используя изолированное хранилище и механизмы
Сохранение состояния игры и загрузка сохранённых состояний – это обычная, необходимая для многих игр процедура. Игры для Windows Phone могут использовать для хранения файлов так называемое изолированное хранилище (
Можно организовать сохранение либо загрузку каких-либо данных, ориентируясь на произвольные события внутри программы, однако, часто эти операции выполняют при запуске (
Жизненный цикл приложения начинается с запуска его пользователем (
Если мы нажмём кнопку Назад во время исполнения приложения, оно будет закрыто (Closing), при этом возврат к приложению невозможен (система не будет сохранять его в памяти, пытаться сохранить промежуточные состояния, как в случае с деактивацией), однако, при возникновении этого события можно
В XNA есть собственные механизмы для обработки состояний приложения. Так, вам уже известен метод Initialize, который выполняется при запуске игры и используется для инициализации игровых параметров. Базовый класс Game предоставляет и другие методы для организации реакции пользователя на изменение состояния игры. В частности, это методы OnActivation (происходит при активации игры), OnDeactivation (при деактивации), Exiting (при выходе из игры).
Для организации работы по загрузке и сохранению игры нам понадобится воспользоваться классом PhoneApplicationService. Обработчики его событий удобно использовать для работы с данными, которые должны быть сохранены при завершении работы игры и загружены при запуске игры. Для
Как будет видно из примера, которым мы займёмся ниже, при запуске XNA-приложения, выполняются методы Initialize и OnActivation. При использовании обработчиков событий из PhoneApplicationService присутствует чёткое разделение при запуске приложения или при его повторной активации. Собственно говоря, это – одна из причин использования PhoneApplicationService в XNA-приложении.
Игра, предусматривающая возможность сохранения игрового состояния, должна предусматривать как минимум два режима работы. Первый – когда игра начинается сначала – в таком случае
Когда объект сериализован, результаты этой операции можно записать в файл. На данном этапе нам понадобится работа с изолированным хранилищем.
При этом, есть возможность сохранять в хранилище любые файлы, работать с каталогами, читать файлы, то есть – пользоваться обычными возможностями System.IO.IsolatedStorage.IsolatedStorageFile (работа с хранилищем) System.IO.IsolatedStorage.IsolatedFileStream (работа с файлами в хранилище). Кроме того, в хранилище можно размещать данные в специальном словаре (содержащем ключи и значения). Эта структура данных называется изолированное хранилище настроек (), работа с хранилищем настроек осуществляется с помощью объекта System.IO.IsolatedStorage.IsolatedStorageSettings.
Напишем простое приложение, позволяющее отслеживать выполнение этих событий и реализующее механизм сохранения состояния приложения. Создадим новый проект P13_1, подключим библиотеки Microsoft.Phone, System.SavedParam.cs. В итоге окно Обозреватель решений для нашего проекта будет выглядеть так, как показано на рис. 19.1.
(рис 19.1) Обозреватель решений для P13_1
В листинге 19.1 приведен код класса SavedParams
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;
//Класс для хранения данных игры, сериализуется
namespace P13_1
{
public class SavedParam
{
const string filename = "SavedParam.xml";
//Игровые данные
//Количество касаний
public int touchCount;
//Позиция касания
public Vector2 touchPos;
public SavedParam()
{
//Установим в значения по умолчанию
touchCount = 0;
touchPos = new Vector2(10, 450);
}
//Процедура сохранения состояния объекта
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 SavedParam Load()
{
//Получим изолированное хранилище
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
//Для хранения ссылки на объект типа SavedParam
SavedParam savedParam;
//Если в хранилище существует файл с нужным именем
if (storage.FileExists(filename))
{
//Откроем файл
IsolatedStorageFileStream stream = storage.OpenFile("SavedParam.xml", FileMode.Open);
//Подготовим механизм для сериализации
XmlSerializer xml = new XmlSerializer(typeof(SavedParam));
//Извлечем данные из файла
savedParam = xml.Deserialize(stream) as SavedParam;
stream.Close();
stream.Dispose();
}
else
{
//Если такого файла нет (при первом запуске в нашем случае)
//Запишем в savedParams ссылку на новый объект типа SavedParams
savedParam = new SavedParam();
}
//Вернём в точку вызова либо результат десериализации, либо - новый объект.
return savedParam;
}
}
}
Класс SavedParam имеет статический метод Load(). Мы вызываем этот метод при запуске или активации игры. В методе делается попытка прочесть файл SavedParam.xml, если файл найден, это означает, что ранее, при выходе из игры или при её деактивации мы сохранили в него результат SavedParam. В таком случае мы десереализуем этот объект и возвращаем его в точку вызова. Если ранее объект сохранён не был, мы создаём новый объект и так же возвращаем его. При создании нового объекта (это происходит при самом первом запуске игры) переменные touchCount и touchPos устанавливаются в значения по умолчанию.
В методе Save() мы сохраняем объект в файл.
Обратите внимание на то, что класс, подлежащий [, в нашем случае это условие исполняется по умолчанию.
Пользуемся этим объектом мы в основном классе игры, его код приведен в листинге 19.2.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
using Microsoft.Phone.Shell;
using System.IO.IsolatedStorage;
namespace P13_1
{
/// <summary>
/// Это главный тип игры
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont myFont;
String text = "";
//Объект, хранящий параметры игры
SavedParam parameters = new SavedParam();
//Счётчик количества запусков
int launchCount = 0;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
// Частота кадра на Windows Phone по умолчанию — 30 кадров в секунду.
TargetElapsedTime = TimeSpan.FromTicks(333333);
// Дополнительный заряд аккумулятора заблокирован.
InactiveSleepTime = TimeSpan.FromSeconds(1);
//Получаем объект PhoneApplicationService, связанный с текущим приложением
PhoneApplicationService appSrv = PhoneApplicationService.Current;
//Назначаем обработчики событий
appSrv.Launching += new EventHandler<LaunchingEventArgs>(appSrv_Launching);
appSrv.Activated += new EventHandler<ActivatedEventArgs>(appSrv_Activated);
appSrv.Deactivated += new EventHandler<DeactivatedEventArgs>(appSrv_Deactivated);
appSrv.Closing += new EventHandler<ClosingEventArgs>(appSrv_Closing);
//Счётчик количества запусков приложения
//Проверим, есть ли данные в хранилище настроек
if (IsolatedStorageSettings.ApplicationSettings.Contains("launchCount") == true)
{
//Если есть - прочитаем
launchCount = (int)IsolatedStorageSettings.ApplicationSettings["launchCount"];
}
//Увеличим на 1 количество запусков
launchCount++;
//Запишем в хранилище (если ранее данных с этим ключом не было, он будет создан)
IsolatedStorageSettings.ApplicationSettings["launchCount"] = launchCount;
//Сохраним данные
IsolatedStorageSettings.ApplicationSettings.Save();
}
//При прекращении работы приложения
void appSrv_Closing(object sender, ClosingEventArgs e)
{
parameters.Save();
}
//При деактивации приложения
void appSrv_Deactivated(object sender, DeactivatedEventArgs e)
{
parameters.Save();
}
//При активации приложения
void appSrv_Activated(object sender, ActivatedEventArgs e)
{
text = text + " srv_Activation";
parameters = SavedParam.Load();
}
//При запуске приложения
void appSrv_Launching(object sender, LaunchingEventArgs e)
{
text = text + " srv_Launching";
parameters = SavedParam.Load();
}
/// <summary>
/// Позволяет игре выполнить инициализацию, необходимую перед запуском.
/// Здесь можно запросить нужные службы и загрузить неграфический
/// контент. Вызов base.Initialize приведет к перебору всех компонентов и
/// их инициализации.
/// </summary>
protected override void Initialize()
{
text = text + " XNA_Initialize";
base.Initialize();
}
//Метод базового класса Game, выполняется при деактивации приложения
protected override void OnDeactivated(object sender, EventArgs args)
{
text = "";
base.OnDeactivated(sender, args);
}
//Метод базового класса Game, выполняется при активации приложения
protected override void OnActivated(object sender, EventArgs args)
{
text = text + " XNA_OnActivated";
base.OnActivated(sender, args);
}
/// <summary>
/// LoadContent будет вызываться в игре один раз; здесь загружается
/// весь контент.
/// </summary>
protected override void LoadContent()
{
// Создайте новый SpriteBatch, который можно использовать для отрисовки текстур.
spriteBatch = new SpriteBatch(GraphicsDevice);
myFont = Content.Load<SpriteFont>("MyFont");
}
/// <summary>
/// UnloadContent будет вызываться в игре один раз; здесь выгружается
/// весь контент.
/// </summary>
protected override void UnloadContent()
{
// ЗАДАЧА: выгрузите здесь весь контент, не относящийся к ContentManager
}
/// <summary>
/// Позволяет игре запускать логику обновления мира,
/// проверки столкновений, получения ввода и воспроизведения звуков.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Update(GameTime gameTime)
{
// Позволяет выйти из игры
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
//Обработакм касание
TouchCollection touchLocations = TouchPanel.GetState();
foreach (TouchLocation touchLocation in touchLocations)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
//Сохраним позицию касания
parameters.touchPos = touchLocation.Position;
//Увеличим количество касаний
parameters.touchCount++;
}
}
base.Update(gameTime);
}
/// <summary>
/// Вызывается, когда игра отрисовывается.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
//Выведем сообщение, сгенерированное при изменении состояния приложения
spriteBatch.DrawString(myFont, text, new Vector2(0, 0), Color.Red);
//Выведем сообщение о количестве касаний в позиции последнего касания
spriteBatch.DrawString(myFont, parameters.touchCount.ToString(), parameters.touchPos, Color.White);
//Выведем данные о количестве запусков программы
spriteBatch.DrawString(myFont, "Launch count = " + launchCount.ToString(), new Vector2(0, 240), Color.Black);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Логика работы данного проекта разъясняется в комментариях, рассмотрим его основные моменты.
В конструкторе класса мы подсчитываем количество запусков игры. Здесь мы работаем с изолированным хранилищем настроек. Сначала проверяем, есть ли в launchCount, если данные есть, приводим их к типу int и записываем в переменную launchCount, после чего увеличиваем переменную на 1 (по умолчанию она равна 0) и записываем значение переменной в хранилище настроек с ключом launchCount. При этом, если такого ключа в хранилище пока нет (при первом запуске) он будет создан. Записав данные, сохраняем состояние хранилища настроек.
В конструкторе мы подключаем обработчики событий , Activated, Deactivated, Closing класса PhoneApplicationService. Эти обработчики мы будем использовать для сохранения состояния игры (Deactivated и Closing) и загрузки (Activated, ). Кроме того, в классе мы переопределили методы базового класса OnActivated и OnDeactivated.
В данном случае это сделано для того, чтобы показать, что при активации приложения после деактивации (то есть, например, в ситуации, когда, работая в приложении мы нажимаем на кнопку вызова домашнего экрана, после чего, воспользовавшись кнопкой Назад возвращаемся в приложение) происходит вызов методов Initialize и OnActivated.
В то же время, при активации после деактивации вызывается лишь обработчик события Activated. При первом запуске приложения происходит вызов Initialize и OnActivated, относящихся к классу Game и из PhoneApplicationService. Мы формируем строку text в этих событиях, она выводится на экран. Для самостоятельного исследования данных методов и особенностей жизненного цикла приложения полезно будет воспользоваться инструментами отладки.
В методе Update мы наблюдаем за касаниями экрана, если касание зафиксировано, записываем в открытую переменную touchPos объекта типа SavedParam координату касания и увеличиваем на 1 значение переменной touchCount из этого же объекта для подсчёта числа касаний.
В методе Draw мы выводим строку, сформированную при исполнении методов, отражающих изменение жизненного цикла приложения, выводим сведения о количестве касаний в позицию последнего зафиксированного касания, пользуясь данными объекта SavedParam, и выводим сведения о количестве запусков программы из переменной launchCount, которая ранее (начиная со второго запуска программы) была установлена с использованием параметра, сохранённого в изолированном хранилище параметров.
На рис. 19.2 вы можете видеть экран программы в эмуляторе.
(рис 19.2) Программа в эмуляторе
Для целей отладки программ, контроля за содержимым изолированного хранилища, можно использовать специальный программный инструмент, который мы сейчас рассмотрим.
Вместе с инструментами разработки для Windows Phone поставляется утилита командной строки ISETool.exe (
Для использования инструмента программа должна быть установлена, но не запущена. Прежде чем им пользоваться, нужно выяснить идентификатор продукта (ProductID). Для этого нужно обратиться к файлу WPAppManifest.xml (он расположен в папке Properties в Обозревателе решений, и найти атрибут ProductID элемента App, на рис. 19.3 приведен фрагмент данного файла для нашего приложения.
(рис 19.3) Фрагмент файла WMAppManifest.xml
Идентификатор, в нашем случае, выглядит как 69ebc0c5-68eb-49a7-b2ca-20beeb988232
Запустим интерпретатор командной строки командой cmd в поле поиска меню Пуск, перейдем в папку, где хранится ISETool.exe (в нашем случае это команда CD C:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Tools\IsolatedStorageExplorerTool и выполним следующую команду, предварительно установив программу на устройство, выйдя из программы, но оставив устройство включённым:
isetool.exe dir de 69ebc0c5-68eb-49a7-b2ca-20beeb988232
В ответ на эту команду мы получим содержимое изолированного хранилища для нашей программы:
<DIR> Shared 255 SavedParam.xml 338 __ApplicationSettings
На рис. 19.4 вы можете видеть окно интерпретатора командной строки после выполнения данной операции.
(рис 19.4) Результат выполнения команды просмотра хранилища
В данном случае команда dir задаёт действие, которое мы хотим выполнить (просмотреть хранилище), команда de указывает на то, что просматривать мы хотим хранилище программы, которая установлена на смартфоне, подключённом к компьютеру, далее следует идентификатор программы.
Для просмотра хранилища программы, установленной на эмуляторе, можно воспользоваться командой xd вместо de. Файлы можно копировать в хранилище с ПК, в обратном направлении, заменять файлы в хранилище. Например, для того, чтобы скопировать файлы из хранилища программы, установленной в эмуляторе, в папку C:\WP, нужно воспользоваться такой командой:
isetool ts xd 69ebc0c5-68eb-49a7-b2ca-20beeb988232 "C:\WP"
При успешном выполнении операции можно увидеть следующие сообщения:
Download Started ... Into Folder: C:\WP
Download Successful Into Folder: C:\WP
На рис. 19.5 вы можете видеть окно интерпретатора командной строки после выполнения команды.
(рис 19.5) Выполнение команды копирования файлов на ПК
(рис 19.6) Локальная копия IsolatedStorage
Получить подсказку по использованию утилиты можно, запустив её без параметров, дополнительные материалы по использованию ISETool можно на http://msdn.microsoft.com/en-us/library/hh286408%28v=vs.92%29.aspx
В данной лабораторной работе мы поговорили о жизненном цикле приложений, о
Организуйте систему сохранения и восстановления состояния игры, разработкой которой вы занимаетесь. Освойте работу с ISETool для контроля за правильностью работы механизмов хранения игровых файлов.
К данной лабораторной работе прилагается видеоурок
и демонстрационный проект.
Цель работы: Научиться сохранять и загружать состояния игр, используя изолированное хранилище и механизмы
Сохранение состояния игры и загрузка сохранённых состояний – это обычная, необходимая для многих игр процедура. Игры для Windows Phone могут использовать для хранения файлов так называемое изолированное хранилище (
Можно организовать сохранение либо загрузку каких-либо данных, ориентируясь на произвольные события внутри программы, однако, часто эти операции выполняют при запуске (
Жизненный цикл приложения начинается с запуска его пользователем (
Если мы нажмём кнопку Назад во время исполнения приложения, оно будет закрыто (Closing), при этом возврат к приложению невозможен (система не будет сохранять его в памяти, пытаться сохранить промежуточные состояния, как в случае с деактивацией), однако, при возникновении этого события можно
В XNA есть собственные механизмы для обработки состояний приложения. Так, вам уже известен метод Initialize, который выполняется при запуске игры и используется для инициализации игровых параметров. Базовый класс Game предоставляет и другие методы для организации реакции пользователя на изменение состояния игры. В частности, это методы OnActivation (происходит при активации игры), OnDeactivation (при деактивации), Exiting (при выходе из игры).
Для организации работы по загрузке и сохранению игры нам понадобится воспользоваться классом PhoneApplicationService. Обработчики его событий удобно использовать для работы с данными, которые должны быть сохранены при завершении работы игры и загружены при запуске игры. Для
Как будет видно из примера, которым мы займёмся ниже, при запуске XNA-приложения, выполняются методы Initialize и OnActivation. При использовании обработчиков событий из PhoneApplicationService присутствует чёткое разделение при запуске приложения или при его повторной активации. Собственно говоря, это – одна из причин использования PhoneApplicationService в XNA-приложении.
Игра, предусматривающая возможность сохранения игрового состояния, должна предусматривать как минимум два режима работы. Первый – когда игра начинается сначала – в таком случае
Когда объект сериализован, результаты этой операции можно записать в файл. На данном этапе нам понадобится работа с изолированным хранилищем.
При этом, есть возможность сохранять в хранилище любые файлы, работать с каталогами, читать файлы, то есть – пользоваться обычными возможностями System.IO.IsolatedStorage.IsolatedStorageFile (работа с хранилищем) System.IO.IsolatedStorage.IsolatedFileStream (работа с файлами в хранилище). Кроме того, в хранилище можно размещать данные в специальном словаре (содержащем ключи и значения). Эта структура данных называется изолированное хранилище настроек (), работа с хранилищем настроек осуществляется с помощью объекта System.IO.IsolatedStorage.IsolatedStorageSettings.
Напишем простое приложение, позволяющее отслеживать выполнение этих событий и реализующее механизм сохранения состояния приложения. Создадим новый проект P13_1, подключим библиотеки Microsoft.Phone, System.SavedParam.cs. В итоге окно Обозреватель решений для нашего проекта будет выглядеть так, как показано на рис. 19.1.
(рис 19.1) Обозреватель решений для P13_1
В листинге 19.1 приведен код класса SavedParams
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;
//Класс для хранения данных игры, сериализуется
namespace P13_1
{
public class SavedParam
{
const string filename = "SavedParam.xml";
//Игровые данные
//Количество касаний
public int touchCount;
//Позиция касания
public Vector2 touchPos;
public SavedParam()
{
//Установим в значения по умолчанию
touchCount = 0;
touchPos = new Vector2(10, 450);
}
//Процедура сохранения состояния объекта
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 SavedParam Load()
{
//Получим изолированное хранилище
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
//Для хранения ссылки на объект типа SavedParam
SavedParam savedParam;
//Если в хранилище существует файл с нужным именем
if (storage.FileExists(filename))
{
//Откроем файл
IsolatedStorageFileStream stream = storage.OpenFile("SavedParam.xml", FileMode.Open);
//Подготовим механизм для сериализации
XmlSerializer xml = new XmlSerializer(typeof(SavedParam));
//Извлечем данные из файла
savedParam = xml.Deserialize(stream) as SavedParam;
stream.Close();
stream.Dispose();
}
else
{
//Если такого файла нет (при первом запуске в нашем случае)
//Запишем в savedParams ссылку на новый объект типа SavedParams
savedParam = new SavedParam();
}
//Вернём в точку вызова либо результат десериализации, либо - новый объект.
return savedParam;
}
}
}
Класс SavedParam имеет статический метод Load(). Мы вызываем этот метод при запуске или активации игры. В методе делается попытка прочесть файл SavedParam.xml, если файл найден, это означает, что ранее, при выходе из игры или при её деактивации мы сохранили в него результат SavedParam. В таком случае мы десереализуем этот объект и возвращаем его в точку вызова. Если ранее объект сохранён не был, мы создаём новый объект и так же возвращаем его. При создании нового объекта (это происходит при самом первом запуске игры) переменные touchCount и touchPos устанавливаются в значения по умолчанию.
В методе Save() мы сохраняем объект в файл.
Обратите внимание на то, что класс, подлежащий [, в нашем случае это условие исполняется по умолчанию.
Пользуемся этим объектом мы в основном классе игры, его код приведен в листинге 19.2.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
using Microsoft.Phone.Shell;
using System.IO.IsolatedStorage;
namespace P13_1
{
/// <summary>
/// Это главный тип игры
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont myFont;
String text = "";
//Объект, хранящий параметры игры
SavedParam parameters = new SavedParam();
//Счётчик количества запусков
int launchCount = 0;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
// Частота кадра на Windows Phone по умолчанию — 30 кадров в секунду.
TargetElapsedTime = TimeSpan.FromTicks(333333);
// Дополнительный заряд аккумулятора заблокирован.
InactiveSleepTime = TimeSpan.FromSeconds(1);
//Получаем объект PhoneApplicationService, связанный с текущим приложением
PhoneApplicationService appSrv = PhoneApplicationService.Current;
//Назначаем обработчики событий
appSrv.Launching += new EventHandler<LaunchingEventArgs>(appSrv_Launching);
appSrv.Activated += new EventHandler<ActivatedEventArgs>(appSrv_Activated);
appSrv.Deactivated += new EventHandler<DeactivatedEventArgs>(appSrv_Deactivated);
appSrv.Closing += new EventHandler<ClosingEventArgs>(appSrv_Closing);
//Счётчик количества запусков приложения
//Проверим, есть ли данные в хранилище настроек
if (IsolatedStorageSettings.ApplicationSettings.Contains("launchCount") == true)
{
//Если есть - прочитаем
launchCount = (int)IsolatedStorageSettings.ApplicationSettings["launchCount"];
}
//Увеличим на 1 количество запусков
launchCount++;
//Запишем в хранилище (если ранее данных с этим ключом не было, он будет создан)
IsolatedStorageSettings.ApplicationSettings["launchCount"] = launchCount;
//Сохраним данные
IsolatedStorageSettings.ApplicationSettings.Save();
}
//При прекращении работы приложения
void appSrv_Closing(object sender, ClosingEventArgs e)
{
parameters.Save();
}
//При деактивации приложения
void appSrv_Deactivated(object sender, DeactivatedEventArgs e)
{
parameters.Save();
}
//При активации приложения
void appSrv_Activated(object sender, ActivatedEventArgs e)
{
text = text + " srv_Activation";
parameters = SavedParam.Load();
}
//При запуске приложения
void appSrv_Launching(object sender, LaunchingEventArgs e)
{
text = text + " srv_Launching";
parameters = SavedParam.Load();
}
/// <summary>
/// Позволяет игре выполнить инициализацию, необходимую перед запуском.
/// Здесь можно запросить нужные службы и загрузить неграфический
/// контент. Вызов base.Initialize приведет к перебору всех компонентов и
/// их инициализации.
/// </summary>
protected override void Initialize()
{
text = text + " XNA_Initialize";
base.Initialize();
}
//Метод базового класса Game, выполняется при деактивации приложения
protected override void OnDeactivated(object sender, EventArgs args)
{
text = "";
base.OnDeactivated(sender, args);
}
//Метод базового класса Game, выполняется при активации приложения
protected override void OnActivated(object sender, EventArgs args)
{
text = text + " XNA_OnActivated";
base.OnActivated(sender, args);
}
/// <summary>
/// LoadContent будет вызываться в игре один раз; здесь загружается
/// весь контент.
/// </summary>
protected override void LoadContent()
{
// Создайте новый SpriteBatch, который можно использовать для отрисовки текстур.
spriteBatch = new SpriteBatch(GraphicsDevice);
myFont = Content.Load<SpriteFont>("MyFont");
}
/// <summary>
/// UnloadContent будет вызываться в игре один раз; здесь выгружается
/// весь контент.
/// </summary>
protected override void UnloadContent()
{
// ЗАДАЧА: выгрузите здесь весь контент, не относящийся к ContentManager
}
/// <summary>
/// Позволяет игре запускать логику обновления мира,
/// проверки столкновений, получения ввода и воспроизведения звуков.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Update(GameTime gameTime)
{
// Позволяет выйти из игры
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
//Обработакм касание
TouchCollection touchLocations = TouchPanel.GetState();
foreach (TouchLocation touchLocation in touchLocations)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
//Сохраним позицию касания
parameters.touchPos = touchLocation.Position;
//Увеличим количество касаний
parameters.touchCount++;
}
}
base.Update(gameTime);
}
/// <summary>
/// Вызывается, когда игра отрисовывается.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
//Выведем сообщение, сгенерированное при изменении состояния приложения
spriteBatch.DrawString(myFont, text, new Vector2(0, 0), Color.Red);
//Выведем сообщение о количестве касаний в позиции последнего касания
spriteBatch.DrawString(myFont, parameters.touchCount.ToString(), parameters.touchPos, Color.White);
//Выведем данные о количестве запусков программы
spriteBatch.DrawString(myFont, "Launch count = " + launchCount.ToString(), new Vector2(0, 240), Color.Black);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Логика работы данного проекта разъясняется в комментариях, рассмотрим его основные моменты.
В конструкторе класса мы подсчитываем количество запусков игры. Здесь мы работаем с изолированным хранилищем настроек. Сначала проверяем, есть ли в launchCount, если данные есть, приводим их к типу int и записываем в переменную launchCount, после чего увеличиваем переменную на 1 (по умолчанию она равна 0) и записываем значение переменной в хранилище настроек с ключом launchCount. При этом, если такого ключа в хранилище пока нет (при первом запуске) он будет создан. Записав данные, сохраняем состояние хранилища настроек.
В конструкторе мы подключаем обработчики событий , Activated, Deactivated, Closing класса PhoneApplicationService. Эти обработчики мы будем использовать для сохранения состояния игры (Deactivated и Closing) и загрузки (Activated, ). Кроме того, в классе мы переопределили методы базового класса OnActivated и OnDeactivated.
В данном случае это сделано для того, чтобы показать, что при активации приложения после деактивации (то есть, например, в ситуации, когда, работая в приложении мы нажимаем на кнопку вызова домашнего экрана, после чего, воспользовавшись кнопкой Назад возвращаемся в приложение) происходит вызов методов Initialize и OnActivated.
В то же время, при активации после деактивации вызывается лишь обработчик события Activated. При первом запуске приложения происходит вызов Initialize и OnActivated, относящихся к классу Game и из PhoneApplicationService. Мы формируем строку text в этих событиях, она выводится на экран. Для самостоятельного исследования данных методов и особенностей жизненного цикла приложения полезно будет воспользоваться инструментами отладки.
В методе Update мы наблюдаем за касаниями экрана, если касание зафиксировано, записываем в открытую переменную touchPos объекта типа SavedParam координату касания и увеличиваем на 1 значение переменной touchCount из этого же объекта для подсчёта числа касаний.
В методе Draw мы выводим строку, сформированную при исполнении методов, отражающих изменение жизненного цикла приложения, выводим сведения о количестве касаний в позицию последнего зафиксированного касания, пользуясь данными объекта SavedParam, и выводим сведения о количестве запусков программы из переменной launchCount, которая ранее (начиная со второго запуска программы) была установлена с использованием параметра, сохранённого в изолированном хранилище параметров.
На рис. 19.2 вы можете видеть экран программы в эмуляторе.
(рис 19.2) Программа в эмуляторе
Для целей отладки программ, контроля за содержимым изолированного хранилища, можно использовать специальный программный инструмент, который мы сейчас рассмотрим.
Вместе с инструментами разработки для Windows Phone поставляется утилита командной строки ISETool.exe (
Для использования инструмента программа должна быть установлена, но не запущена. Прежде чем им пользоваться, нужно выяснить идентификатор продукта (ProductID). Для этого нужно обратиться к файлу WPAppManifest.xml (он расположен в папке Properties в Обозревателе решений, и найти атрибут ProductID элемента App, на рис. 19.3 приведен фрагмент данного файла для нашего приложения.
(рис 19.3) Фрагмент файла WMAppManifest.xml
Идентификатор, в нашем случае, выглядит как 69ebc0c5-68eb-49a7-b2ca-20beeb988232
Запустим интерпретатор командной строки командой cmd в поле поиска меню Пуск, перейдем в папку, где хранится ISETool.exe (в нашем случае это команда CD C:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Tools\IsolatedStorageExplorerTool и выполним следующую команду, предварительно установив программу на устройство, выйдя из программы, но оставив устройство включённым:
isetool.exe dir de 69ebc0c5-68eb-49a7-b2ca-20beeb988232
В ответ на эту команду мы получим содержимое изолированного хранилища для нашей программы:
<DIR> Shared 255 SavedParam.xml 338 __ApplicationSettings
На рис. 19.4 вы можете видеть окно интерпретатора командной строки после выполнения данной операции.
(рис 19.4) Результат выполнения команды просмотра хранилища
В данном случае команда dir задаёт действие, которое мы хотим выполнить (просмотреть хранилище), команда de указывает на то, что просматривать мы хотим хранилище программы, которая установлена на смартфоне, подключённом к компьютеру, далее следует идентификатор программы.
Для просмотра хранилища программы, установленной на эмуляторе, можно воспользоваться командой xd вместо de. Файлы можно копировать в хранилище с ПК, в обратном направлении, заменять файлы в хранилище. Например, для того, чтобы скопировать файлы из хранилища программы, установленной в эмуляторе, в папку C:\WP, нужно воспользоваться такой командой:
isetool ts xd 69ebc0c5-68eb-49a7-b2ca-20beeb988232 "C:\WP"
При успешном выполнении операции можно увидеть следующие сообщения:
Download Started ... Into Folder: C:\WP
Download Successful Into Folder: C:\WP
На рис. 19.5 вы можете видеть окно интерпретатора командной строки после выполнения команды.
(рис 19.5) Выполнение команды копирования файлов на ПК
(рис 19.6) Локальная копия IsolatedStorage
Получить подсказку по использованию утилиты можно, запустив её без параметров, дополнительные материалы по использованию ISETool можно на http://msdn.microsoft.com/en-us/library/hh286408%28v=vs.92%29.aspx
В данной лабораторной работе мы поговорили о жизненном цикле приложений, о
Организуйте систему сохранения и восстановления состояния игры, разработкой которой вы занимаетесь. Освойте работу с ISETool для контроля за правильностью работы механизмов хранения игровых файлов.
К данной лабораторной работе прилагается видеоурок
и демонстрационный проект.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.