|
Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить..... |
Работа с файлами, сериализация
Задачи работы
- Освоить файловые операции в XNA
- Освоить сериализацию объектов
- Организовать загрузку и сохранение игры
Файловые операции в XNA
Создадим новый проект P10_1. Реализуем в нем демонстрацию следующих операций с файлами:
Создание нового файла.
Открытие файла и чтение информации из него.
Переименование файла
Просмотр директории
Для работы с файлами в XNA нужно выполнить следующие шаги:
Во-первых – получить объект типа IAsyncResult – как результат запроса о выборе устройства хранения информации.
Во-вторых – переменная типа IAsyncResult используется для создания переменной типа StorageDevice, которая представляет устройство для хранения данных.
В-третьих – переменная типа StorageDevice используется при создании объекта StorageContainer, который используется для доступа к месту хранения файлов. В случае с Windows-играми это – папка SavedGames, расположенная в папке Мои Документы текущего пользователя.
На рис. 14.1. вы можете видеть данную папку для проекта P10_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
В обычных файлах можно хранить различные данные, в том числе – информацию об уровнях, информацию для сохранения игры и т.д. Однако при таком подходе вся работа по восстановлению необходимых данных ложится на программиста. Удобнее было бы сохранять и восстанавливать не отдельные переменные или поля объектов, а целые объекты, которые хранят множество полей, используемых в игре. Сделать это позволяет сериализация объектов.
