Невозможно пройти тесты, в окне с вопросами пусто |
Сохранение и загрузка игр, сериализация, работа с файлами
Пользуемся этим объектом мы в основном классе игры, его код приведен в листинге 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 вы можете видеть экран программы в эмуляторе.
Для целей отладки программ, контроля за содержимым изолированного хранилища, можно использовать специальный программный инструмент, который мы сейчас рассмотрим.