Спонсор: Microsoft
Опубликован: 10.04.2009 | Доступ: свободный | Студентов: 3208 / 229 | Оценка: 4.49 / 4.39 | Длительность: 17:21:00
Специальности: Программист
Самостоятельная работа 10:

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

Аннотация: Практически все игры используют какие-либо внешние данные. В частности, подавляющее большинство игр содержит возможности сохранения игрового процесса в его текущем состоянии и его загрузки, игры хранят во внешних файлах статистические данные, загружают из файлов дополнительные уровни. XNA содержит инструментарий, предназначенный для работы с файлами. В этой лабораторной работе мы рассмотрим файловые операции, доступные в XNA, а так же – сериализацию объектов – мощное средство, которое можно использовать для сохранения и загрузки игровых данных.

Примеры к лабораторной работе

Задачи работы

  • Освоить файловые операции в XNA
  • Освоить сериализацию объектов
  • Организовать загрузку и сохранение игры

Файловые операции в XNA

Создадим новый проект P10_1. Реализуем в нем демонстрацию следующих операций с файлами:

Создание нового файла.

Открытие файла и чтение информации из него.

Копирование файла.

Переименование файла

Просмотр директории

Удаление файла

Для работы с файлами в XNA нужно выполнить следующие шаги:

Во-первых – получить объект типа IAsyncResult – как результат запроса о выборе устройства хранения информации.

Во-вторых – переменная типа IAsyncResult используется для создания переменной типа StorageDevice, которая представляет устройство для хранения данных.

В-третьих – переменная типа StorageDevice используется при создании объекта StorageContainer, который используется для доступа к месту хранения файлов. В случае с Windows-играми это – папка SavedGames, расположенная в папке Мои Документы текущего пользователя.

На рис. 14.1. вы можете видеть данную папку для проекта P10_1.

Папка для сохранения игры

увеличить изображение
Рис. 14.1. Папка для сохранения игры

В листинге 14.1. вы можете найти код класса Game1.

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;
namespace P10_1
{
    
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        //Для информации об используемом устройстве хранения информации
        StorageDevice sDev;
        //Для хранения результата асинхронной операции доступа к устройству
        IAsyncResult res;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
        }

        
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }
        //Процедура для создания нового файла
        void FileCreate(StorageDevice device)
        {
         //Массив байтов для записи в файл
            byte[] a = new byte[10];
            for (byte i = 0; i < 10; i++)
            {
                a[i] = i;
            }
            //Открываем контейнер для хранения файлов
            //В случае с Windows-играми это - папка с соответствующим
            //именем в папке Мои документы текущего пользователя
            StorageContainer container =
                device.OpenContainer("P10_1");
            //Соединяем имя файла и имя контейнера
            string filename = Path.Combine(container.Path, "savegame.sav");
            //Создаем новый файл

            if (!File.Exists(filename))
            {

                FileStream file = File.Create(filename);
                //Записываем в файл массив байтов, сгенерированный выше
                file.Write(a, 0, 10);
                //закрываем файл
                file.Close();
                this.Window.Title = "Файл создан";
            }
            else
            {
                this.Window.Title = "Файл уже создан";
            }

            //Уничтожаем контейнер - только после этого файл будет 
            //сохранен
            container.Dispose();
            
        }

        //Процедура для открытия существующего файла
        void FileOpen(StorageDevice device)
        {
            StorageContainer container =
                device.OpenContainer("P10_1");
            string filename = Path.Combine(container.Path, "savegame.sav");

            if (File.Exists(filename))
            {

                FileStream file = File.Open(filename, FileMode.Open);
                //Выведем данные, считанные из файла, в заголовок игрового окна
                this.Window.Title = "Содержимое файла: ";
                for (int i = 1; i < file.Length + 1; i++)
                    this.Window.Title = this.Window.Title + file.ReadByte().ToString();
                file.Close();
            }
            else
            {
                this.Window.Title = "Отсутствует файл для чтения";
            }
            container.Dispose();
        }
        //Процедура для копирования файла
        void FileCopy(StorageDevice device)
        {
            StorageContainer container =
                device.OpenContainer("P10_1");
            string filename = Path.Combine(container.Path, "savegame.sav");

            if (File.Exists(filename))
            {
                string copyfilename = Path.Combine(container.Path, "copysave.bak");
                File.Copy(filename, copyfilename, true);
                this.Window.Title = "Файл скопирован";
            }
            else
            {
                this.Window.Title = "Файл не существует";
            }
            container.Dispose();
            
        }
        //Процедура для переименования файла
        void FileRename(StorageDevice device)
        {
              StorageContainer container =
                device.OpenContainer("P10_1");
            //Старое имя файла
            string oldfilename = Path.Combine(container.Path, "copysave.bak");
            //Новое имя файла
            string newfilename = Path.Combine(container.Path, "rencopysave.sav");
            //Если в папке нет файла с новым именем файла и есть файл 
            //со старым именем - переименовываем

            if (!File.Exists(newfilename)&File .Exists (oldfilename ))
            {
                File.Move(oldfilename, newfilename);
                this.Window.Title = "Скопированный файл переименован";
            }
            else
            {
                this.Window.Title = "Такой файл уже есть или отсутствует файл для переименования";
            }
               
            container.Dispose();
            
        }
        //Просмотр содержимого папки
        void FileEnumerate(StorageDevice device)
        {
            StorageContainer container =
                device.OpenContainer("P10_1");
            string FNForComp="";
            //Получить список файлов
            ICollection<string> FileList = Directory.GetFiles(container.Path);
            //Для каждого имени файла проверим, соответствует ли оно
            //заданному имени, предположим, что папка не содержит заданного файла
            this.Window.Title = "Папка не содержит файл rencopysave.sav";
            foreach (string filename in FileList)
            {
                //Извлечем из строки с полным путем к файлу
                //имя файла
                FNForComp = Path.GetFileName(filename);
                //Если имя файла равно искомому - выведем 
                //соответствующее сообщение
                if (FNForComp == "rencopysave.sav")
                {
                    this.Window.Title = "Папка содержит файл rencopysave.sav"; 
                }
            }
            container.Dispose();
        }
        //удаление файла
        void FileDelete(StorageDevice device)
        {

            StorageContainer container =
                device.OpenContainer("P10_1");
            string filename = Path.Combine(container.Path, "rencopysave.sav");

            //Удаляем файл если он существует
            if (File.Exists(filename))
            {
                File.Delete(filename);
                this.Window.Title = "Файл rencopysave.sav удален";
            }
            container.Dispose();
        }

        
        protected override void Update(GameTime gameTime)
        {

            KeyboardState kb = Keyboard.GetState();
            //Инициируем процедуру выбора устройства, в случае с Windows
            //автоматически выбирается папка SavedGames в папке Мои документы
            //текущего пользователя
            res = Guide.BeginShowStorageDeviceSelector(PlayerIndex.One, null, null);
            //Сохраняем найденное устройство - позже мы используем его 
            //в процедурах работы с файлами
            sDev = Guide.EndShowStorageDeviceSelector(res);
            //При нажатии на клавишу Q вызываем процедуру сохранения файла
            if (kb.IsKeyDown(Keys.Q))
            {
                FileCreate(sDev);
            }
            //При нажатии на W вызываем процедуру открытия файла
            if (kb.IsKeyDown(Keys.W))
            {
                FileOpen(sDev);
            }
            //При нажатии на E вызываем процедуру копирования файла
            if (kb.IsKeyDown(Keys.E))
            {
                FileCopy(sDev);
            }
            //При нажатии на A вызываем процедуру переименования файла
            if (kb.IsKeyDown(Keys.A))
            {
                FileRename(sDev);
            }
            //При нажатии на S вызываем процедуру просмотра каталога
            if (kb.IsKeyDown(Keys.S))
            {
                FileEnumerate(sDev);
            }
            //При нажатии D вызываем процедуру удаления файла
            if (kb.IsKeyDown(Keys.D))
            {
                FileDelete(sDev);
            }
            base.Update(gameTime);
        }

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

            // TODO: Add your drawing code here

            base.Draw(gameTime);
        }
    }
}
Листинг 14.1. Код класса Game1

В обычных файлах можно хранить различные данные, в том числе – информацию об уровнях, информацию для сохранения игры и т.д. Однако при таком подходе вся работа по восстановлению необходимых данных ложится на программиста. Удобнее было бы сохранять и восстанавливать не отдельные переменные или поля объектов, а целые объекты, которые хранят множество полей, используемых в игре. Сделать это позволяет сериализация объектов.

Alina Lasskaja
Alina Lasskaja

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