Спонсор: Microsoft
Опубликован: 10.04.2009 | Уровень: специалист | Доступ: свободно
Самостоятельная работа 10:

Работа с файлами, сериализация

Механизмы сериализации и игровая логика реализованы в коде класса Game1. Его вы можете видеть в листинге 14.5.

using System;
using System.Collections.Generic;
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.Net;
using Microsoft.Xna.Framework.Storage;
//Классы для работы с устройствами ввода-вывода
using System.IO;
//Классы для работы механизмов сериализации
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace P10_2
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        //Для текстуры стены
        Texture2D txtWall;
        //Прямоугольник для создания объектов Wall
        Rectangle recSprite = new Rectangle(0, 0, 64, 64);
        //Массив объектов Wall
        Wall [,] arrayOfWalls;
        //Объект, хранящий игровые данные и подлежащий сериализации
        //Массив в этом объекте используется при загрузке игры и 
        //при сохранении игры, в игровом процессе используется
        //массив объектов Wall
        GameData MyObj;
        //Переменная для хранения состояния мыши
        MouseState mouse;
        //устройство для хранения информации
        StorageDevice sDev;
        //результат операции доступа к устройству
        IAsyncResult res;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
       
        protected override void Initialize()
        {
            //Разрешение экрана 640х512
            graphics.PreferredBackBufferWidth = 640;
            graphics.PreferredBackBufferHeight = 512;
            graphics.ApplyChanges();
            //Сделать указатель мыши видимым
            this.IsMouseVisible = true;
            base.Initialize();
        }

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            Services.AddService(typeof(SpriteBatch), spriteBatch);
            txtWall = Content.Load<Texture2D>("wall");
            //В этом массиве лишь единицы - это значит
            //что при запуске все игровое поле заполнено
            //изображениями стен
            byte [,] arrayForGame  = new byte[8, 10] { 
            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, 
            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, 
            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, 
            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, 
            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, 
            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
            };
            //Новый массив стен
            arrayOfWalls = new Wall[8, 10];
            //Создаем объект для хранения данных,
            //передавая ему массив
            MyObj = new GameData(arrayForGame);
            //вызываем процедуру создания и 
            //вывода на экран игровых объектов
            AddSprites ();
        }
        //Создание игровых объектов
        void AddSprites()
        {
            //Просматриваем массив array в объекте типа GameData
            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 10; j++)
                {
                    if (MyObj.array[i, j] == 1)
                    {
                        //Если в массиве единица - создаем новый объект в текущей ячейке
                        //массива arrayOfWalls и добавляем в список игровых компонентов
                        arrayOfWalls[i, j] = new Wall(this, ref txtWall, new Vector2(j, i), recSprite);
                        Components.Add(arrayOfWalls[i, j]);
                    }
                }
            }
        }
        //Процедура очистки массива игровых компонентов
        void ClearAll()
        {
            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 10; j++)
                {
                    if (arrayOfWalls[i, j] != null)
                    {
                        arrayOfWalls[i, j].Dispose();
                        arrayOfWalls[i, j] = null;
                    }
                }
            }
            
        }
        //Процедура проверки массива игровых компонентов и отражения
        //его состояния в массиве объекта типа GameData
        //в нашем случае, если ячейка массива игровых компонентов содержит
        //объект, в массив объекта GameData записывают 1, если нет - 0
        void SetWallToArray()
        {
            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 10; j++)
                {
                    if (arrayOfWalls[i, j] == null)
                    {
                        MyObj.array[i, j] = 0;
                    }
                    else
                    {
                        MyObj.array[i, j] = 1;
                    }
                }
            }
        }
        //Процедура сериализации объекта
        void serializ()
        {
            //Контейнер для хранения данных
            StorageContainer container = sDev.OpenContainer("P10_2");
            //Полное имя файла - комбинация адреса контейнера и имени
            string filename = Path.Combine(container.Path, "savegame.sav");
            //Объект, предназначенный для сериализации и десериализации других объектов
            IFormatter formatter = new BinaryFormatter();
            //Создаем новый поток для записи файла
            Stream stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None);
            //Сериализуем объект MyObj в поток stream
            formatter.Serialize(stream, MyObj);
            //Закрываем поток
            stream.Close();
            //Уничтожаем контейнер
            container.Dispose();
            //выводим сообщение в заголовок игрового окна
            this.Window.Title = "Игра сохранена";
        }
        //Процедура десериализации объекта
        //похожа на процедуру десериализации
        //при десериализации файл открывают для чтения и 
        //десериализуют в объект
        void deserializ()
        {
            StorageContainer container = sDev.OpenContainer("P10_2");
            string filename = Path.Combine(container.Path, "savegame.sav");
            IFormatter formatter = new BinaryFormatter();
            //Новый поток для чтения файла
            Stream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
            //Получаем данные из потока и приводим их к типу MyObj
            MyObj = (GameData)formatter.Deserialize(stream);
            stream.Close();
            container.Dispose();
            this.Window.Title = "Игра загружена";
        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

     
        protected override void Update(GameTime gameTime)
        {
            //получим состояние клавиатуры
            KeyboardState kb = Keyboard.GetState();
            //Сохраняем игру при нажатой клавише A
            if (kb.IsKeyDown(Keys.A))
            {
                //Отразим состояние игровго окна в массиве объекта типа GameData
                SetWallToArray();
                //Получим устройство для хранения данных
                res = Guide.BeginShowStorageDeviceSelector(PlayerIndex.One, null, null);
                sDev = Guide.EndShowStorageDeviceSelector(res);
                //Вызовем процедуру сериализации
                serializ ();
            }
            //Загружаем игру при нажатой клавише W
            if (kb.IsKeyDown (Keys .W ))
            {
                //Очищаем игровой экран
                ClearAll();
                //Получим устройство для хранения данных
                res = Guide.BeginShowStorageDeviceSelector(PlayerIndex.One, null, null);
                sDev = Guide.EndShowStorageDeviceSelector(res);
                //Десериализуем объект из файла
                deserializ();
                //Сконструируем игровой экран на основе десериализованного 
                //объекта MyObj
                AddSprites();
            }
            //Работа с мышью
            mouse = Mouse.GetState();
            if (mouse.LeftButton == ButtonState.Pressed)
            {
                for (int i = 0; i < 8; i++)
                {
                    for (int j = 0; j < 10; j++)
                    {
                        //Если в текущей ячейке массива есть "стена"
                        //проверим, находился ли указатель мыши в пределах объекта
                        //соответствующего текущей ячейке. Если да - уничтожим объект
                        if (arrayOfWalls[i, j] != null)
                        {
                            if (arrayOfWalls[i, j].sprPosition.X + arrayOfWalls[i, j].sprRectangle.Width > mouse.X &&
                                arrayOfWalls[i, j].sprPosition.X < mouse.X &&
                                arrayOfWalls[i, j].sprPosition.Y + arrayOfWalls[i, j].sprRectangle.Height > mouse.Y &&
                                arrayOfWalls[i, j].sprPosition.Y < mouse.Y)
                            {
                                arrayOfWalls[i, j].Dispose();
                                arrayOfWalls[i, j] = null;
                            }
                        }
                    }
                }
            }
            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();
            base.Draw(gameTime);
            spriteBatch.End();
        }

    }
}
Листинг 14.5. Код класса Game1

На рис. 14.3. вы можете видеть игровой экран проекта P10_2.

Игровой экран проекта P10_2

увеличить изображение
Рис. 14.3. Игровой экран проекта P10_2
Alina Lasskaja
Alina Lasskaja

Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить.....