| Невозможно пройти тесты, в окне с вопросами пусто |
Сохранение и загрузка игр, сериализация, работа с файлами
Пользуемся этим объектом мы в основном классе игры, его код приведен в листинге 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);
}
}
}
Листинг
19.2.
Код класса Game1
Логика работы данного проекта разъясняется в комментариях, рассмотрим его основные моменты.
В конструкторе класса мы подсчитываем количество запусков игры. Здесь мы работаем с изолированным хранилищем настроек. Сначала проверяем, есть ли в хранилище данные по ключу launchCount, если данные есть, приводим их к типу int и записываем в переменную launchCount, после чего увеличиваем переменную на 1 (по умолчанию она равна 0) и записываем значение переменной в хранилище настроек с ключом launchCount. При этом, если такого ключа в хранилище пока нет (при первом запуске) он будет создан. Записав данные, сохраняем состояние хранилища настроек.
В конструкторе мы подключаем обработчики событий Launching, Activated, Deactivated, Closing класса PhoneApplicationService. Эти обработчики мы будем использовать для сохранения состояния игры (Deactivated и Closing) и загрузки (Activated, Launching). Кроме того, в классе мы переопределили методы базового класса OnActivated и OnDeactivated.
В данном случае это сделано для того, чтобы показать, что при активации приложения после деактивации (то есть, например, в ситуации, когда, работая в приложении мы нажимаем на кнопку вызова домашнего экрана, после чего, воспользовавшись кнопкой Назад возвращаемся в приложение) происходит вызов методов Initialize и OnActivated.
В то же время, при активации после деактивации вызывается лишь обработчик события Activated. При первом запуске приложения происходит вызов Initialize и OnActivated, относящихся к классу Game и Launching из PhoneApplicationService. Мы формируем строку text в этих событиях, она выводится на экран. Для самостоятельного исследования данных методов и особенностей жизненного цикла приложения полезно будет воспользоваться инструментами отладки.
В методе Update мы наблюдаем за касаниями экрана, если касание зафиксировано, записываем в открытую переменную touchPos объекта типа SavedParam координату касания и увеличиваем на 1 значение переменной touchCount из этого же объекта для подсчёта числа касаний.
В методе Draw мы выводим строку, сформированную при исполнении методов, отражающих изменение жизненного цикла приложения, выводим сведения о количестве касаний в позицию последнего зафиксированного касания, пользуясь данными объекта parameters типа SavedParam, и выводим сведения о количестве запусков программы из переменной launchCount, которая ранее (начиная со второго запуска программы) была установлена с использованием параметра, сохранённого в изолированном хранилище параметров.
На рис. 19.2 вы можете видеть экран программы в эмуляторе.
Для целей отладки программ, контроля за содержимым изолированного хранилища, можно использовать специальный программный инструмент, который мы сейчас рассмотрим.
