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