Уровень – это подгружаемые данные, никто не хранит их всех в памяти как и в основном исходном коде. Будем учиться писать уровень который будет читаться с файла.
Только не нужно пропускать статью со словами «Что нам стоить прочитать с файла…», Читать будем с помощью сериализации. Почему? Потому, что нужно сразу привыкать к хорошему или правильному. На консоле будет сложно прочитать данные старыми методами. Можно, но сложно поэтому вспоминаем, а для кого-то учим XML, структуры в ней, и методы сбора информации.
Среда: Microsoft Visual Studio C# 2008 Express Edition, XNA 3.1
Проект, как это будет реализовано?
Имеем категорию levels, файл level_001.xml
В файле нацарапано:
Position – Координаты объекта
Rotation – Вращение объекта
TypeName – Тип объекта
В программе должен быть описан каждый тип объекта. Я опишу три простейших:
class Land:LevelElement Элемент уровня: земля
class Box:LevelElement Элемент уровня: ящик
class Circle:LevelElement Элемент уровня: круг
Теперь общее представление программной структуры:
Самый главный класс – Игровой менеджер (GameManager), который содержит множество игровых элементов (GameElement). Игровой элемент может быть уровень, игрок, фон, даже элемент уровня в общем все зависит от вашей фантазии. Мы, для краткости, рассмотрим только одну вариацию – уровень (Level). Уровень в свою очередь может содержать множество элементов уровня (LevelElement). Вот они наши вариации Ящик(Box), Земля(Land), Круг(Circle). Создается игровой элемент не просто так, а добавляется в коллекцию учитывая промежуточные значения класса LevelReadElement, куда заноситься данные из файла.
Структура решения
Для большей зрелищности я добавил текстуры к элементам уровня, а так же подключил через библиотеку Farseer Physics физические свойства элементов - будут падать.
Теперь ближе к файлам, комментарии в коде.
Game1.cs
Только не нужно пропускать статью со словами «Что нам стоить прочитать с файла…», Читать будем с помощью сериализации. Почему? Потому, что нужно сразу привыкать к хорошему или правильному. На консоле будет сложно прочитать данные старыми методами. Можно, но сложно поэтому вспоминаем, а для кого-то учим XML, структуры в ней, и методы сбора информации.
Среда: Microsoft Visual Studio C# 2008 Express Edition, XNA 3.1
Проект, как это будет реализовано?
Имеем категорию levels, файл level_001.xml
В файле нацарапано:
Каждый элемент уровня имеет несколько параметров:0 600 0 Land 100 100 1 Box 400 100 0 Box 600 100 0 Circle 700 100 0 Circle
Position – Координаты объекта
Rotation – Вращение объекта
TypeName – Тип объекта
В программе должен быть описан каждый тип объекта. Я опишу три простейших:
class Land:LevelElement Элемент уровня: земля
class Box:LevelElement Элемент уровня: ящик
class Circle:LevelElement Элемент уровня: круг
Теперь общее представление программной структуры:
Самый главный класс – Игровой менеджер (GameManager), который содержит множество игровых элементов (GameElement). Игровой элемент может быть уровень, игрок, фон, даже элемент уровня в общем все зависит от вашей фантазии. Мы, для краткости, рассмотрим только одну вариацию – уровень (Level). Уровень в свою очередь может содержать множество элементов уровня (LevelElement). Вот они наши вариации Ящик(Box), Земля(Land), Круг(Circle). Создается игровой элемент не просто так, а добавляется в коллекцию учитывая промежуточные значения класса LevelReadElement, куда заноситься данные из файла.
Структура решения
Для большей зрелищности я добавил текстуры к элементам уровня, а так же подключил через библиотеку Farseer Physics физические свойства элементов - будут падать.
Теперь ближе к файлам, комментарии в коде.
Game1.cs
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.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; using Serialization.GameManagers; using Serialization.Levels; namespace Serialization { public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; GameManager gameManager; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; graphics.PreferredBackBufferWidth = 1280; graphics.PreferredBackBufferHeight = 720; gameManager = new GameManager(this, graphics); gameManager.Add(new Level()); Components.Add(gameManager); } protected override void Initialize() { base.Initialize(); } protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); } protected override void UnloadContent() { } protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); base.Update(gameTime); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); base.Draw(gameTime); } } }GameManager.cs
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.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; using FarseerGames.FarseerPhysics; using FarseerGames.FarseerPhysics.Interfaces; using FarseerGames.FarseerPhysics.Dynamics; using FarseerGames.FarseerPhysics.Collisions; using FarseerGames.FarseerPhysics.Factories; namespace Serialization.GameManagers { ///GameElement.cs/// Игровой менеджер /// class GameManager: DrawableGameComponent { ////// Список игровых элементов /// Listelements; /// /// Инициализирован ли менеджер /// public bool IsInitialized; ////// Чудо рисователь /// public SpriteBatch spriteBatch; ////// Контент загрузчик /// public ContentManager contentManager; ////// Графическое устройство /// public GraphicsDeviceManager graphicDeviceManager; ////// Физический симулятор /// public PhysicsSimulator physicsSimulator; ////// Конструктор /// /// Игра/// Менеджер Графического устройстваpublic GameManager(Game game, GraphicsDeviceManager graphicDeviceManager) : base(game) { elements = new List(); IsInitialized = false; this.graphicDeviceManager = graphicDeviceManager; physicsSimulator = new PhysicsSimulator(new Vector2(0, 1000)); } /// /// Инициализация /// public override void Initialize() { base.Initialize(); this.IsInitialized = true; } ////// Загрузка данных /// protected override void LoadContent() { base.LoadContent(); contentManager = Game.Content; spriteBatch = new SpriteBatch(GraphicsDevice); foreach (GameElement element in elements) element.LoadContent(); } ////// Выгрузка данных /// protected override void UnloadContent() { foreach (GameElement element in elements) element.UnLoadContent(); base.UnloadContent(); } ////// Обновление данных /// /// Игровое времяpublic override void Update(GameTime gameTime) { base.Update(gameTime); foreach (GameElement element in elements) element.Update(gameTime); physicsSimulator.Update(gameTime.ElapsedGameTime.Milliseconds * 0.001f); } ////// Отображение данных /// /// Игровое времяpublic override void Draw(GameTime gameTime) { base.Draw(gameTime); GraphicsDevice.Clear(Color.Black); foreach (GameElement element in elements) element.Draw(gameTime); } ////// Добавление Игрового элемента /// /// Игровой элементpublic void Add(GameElement element) { element.gameManager = this; if (IsInitialized) element.LoadContent(); elements.Add(element); } ////// Удаление Игрового элемента /// /// Игровой элементpublic void Remove(GameElement element) { element.UnLoadContent(); elements.Remove(element); } } }
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.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; using FarseerGames.FarseerPhysics; using FarseerGames.FarseerPhysics.Interfaces; using FarseerGames.FarseerPhysics.Dynamics; using FarseerGames.FarseerPhysics.Collisions; using FarseerGames.FarseerPhysics.Factories; namespace Serialization.GameManagers { ///Level.cs/// Элемент игры (базовый класс) /// class GameElement { ////// Принадлежность игровому Менеджеру /// public GameManager gameManager; ////// Конструктор /// public GameElement() { } ////// Загрузка данных /// public virtual void LoadContent() { } ////// Выгрузка данных /// public virtual void UnLoadContent() { } ////// Обновление данных /// /// Игровое времяpublic virtual void Update(GameTime gameTime) { } ////// Отображение данных /// /// Игровое времяpublic virtual void Draw(GameTime gameTime) { } } }
using System; using System.Collections.Generic; using System.Linq; using System.IO; using System.Xml; using System.Xml.Serialization; 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.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; using FarseerGames.FarseerPhysics; using FarseerGames.FarseerPhysics.Interfaces; using FarseerGames.FarseerPhysics.Dynamics; using FarseerGames.FarseerPhysics.Collisions; using FarseerGames.FarseerPhysics.Factories; using Serialization.GameManagers; using Serialization.Levels.LevelElements; namespace Serialization.Levels { ///LevelElement.cs/// Уровень /// class Level:GameElement { ////// Список елементов в уровне /// public Listelements; /// /// Конструктор /// public Level() { elements = new List(); } /// /// Загрузка ресурсов элементов в уровне /// public override void LoadContent() { //foreach (LevelElement element in elements) //element.LoadContent(); /*Box box = new Box(); LevelReadElement r = new LevelReadElement(); r.Position = new Vector2(100, 100); r.Rotation = 1; r.TypeName = "Box"; box.level = this; box.LoadContent(r); Add(box); Add(box);*/ ReadLevel("level_001.xml"); } ////// Выгрузка элементов уровня /// public override void UnLoadContent() { foreach (LevelElement element in elements) element.UnLoadContent(); } ////// Обновление элементов уровня /// /// Игровое времяpublic override void Update(GameTime gameTime) { foreach (LevelElement element in elements) element.Update(gameTime); } ////// Отображение Элементов уровня /// /// Игровое времяpublic override void Draw(GameTime gameTime) { foreach (LevelElement element in elements) element.Draw(gameTime); } ////// Добавление элемента к уровню /// /// Элемент уровняpublic void Add(LevelElement element) { element.level = this; elements.Add(element); } ////// Удаление элемента из уровня /// /// Элемент уровняpublic void Remove(LevelElement element) { element.UnLoadContent(); elements.Remove(element); } ////// Загрузка элементов из файла /// /// Название файла (путь к файлу)public void ReadLevel(string path) { Listlist = new List (); string filename = System.IO.Path.Combine("levels", path); FileStream stream = File.Open(filename, FileMode.Open); XmlSerializer serializer = new XmlSerializer(typeof(List )); list = (List )serializer.Deserialize(stream); stream.Close(); foreach (LevelReadElement element in list) { if (element.TypeName == "Box") { Box levEl = new Box(); levEl.level = this; levEl.LoadContent(element); Add(levEl); } else if (element.TypeName == "Circle") { Circle levEl = new Circle(); levEl.level = this; levEl.LoadContent(element); Add(levEl); } else if (element.TypeName == "Land") { Land levEl = new Land(); levEl.level = this; levEl.LoadContent(element); Add(levEl); } } } /// /// Запись элементов в файл /// /// Название файла (путь к файлу)public void SaveLevel(string path) { Listlist = new List (); LevelReadElement el; foreach (LevelElement element in elements) { el = new LevelReadElement(); el.TypeName = element.TypeName; el.Position = element.body[0].Position; el.Rotation = element.body[0].Rotation; list.Add(el); } string filename = System.IO.Path.Combine("levels", path); FileStream stream = File.Open(filename, FileMode.OpenOrCreate); XmlSerializer serializer = new XmlSerializer(typeof(List )); serializer.Serialize(stream, list); stream.Close(); } } }
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.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; using FarseerGames.FarseerPhysics; using FarseerGames.FarseerPhysics.Interfaces; using FarseerGames.FarseerPhysics.Dynamics; using FarseerGames.FarseerPhysics.Collisions; using FarseerGames.FarseerPhysics.Factories; namespace Serialization.Levels { ///LevelReadElement.cs/// Один элемент уровня /// class LevelElement { ////// Ссылка на принадлежность уровню /// public Level level; ////// Список тел элемента /// public List body; ////// Список геометрий /// public Listgeom; /// /// Текстовое название элемента /// public string TypeName; ////// Констуктор /// public LevelElement() { TypeName = "none"; body = new List(); geom = new List(); } /// /// Загрузка данных /// public virtual void LoadContent(LevelReadElement element) { } ////// Выгрузка данных /// public virtual void UnLoadContent() { } ////// Обновление данных /// /// Игровое времяpublic virtual void Update(GameTime gameTime) { } ////// Отображение данных /// /// Игровое времяpublic virtual void Draw(GameTime gameTime) { } } }
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.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; using FarseerGames.FarseerPhysics; using FarseerGames.FarseerPhysics.Interfaces; using FarseerGames.FarseerPhysics.Dynamics; using FarseerGames.FarseerPhysics.Collisions; using FarseerGames.FarseerPhysics.Factories; namespace Serialization.Levels { ///Box.cs/// Читаемый элемент уровня из файла /// [Serializable] public class LevelReadElement { ////// Координатная позиция /// public Vector2 Position; ////// Вращение /// public float Rotation; ////// Текстовое название елемента /// public string TypeName; } }
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.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; using FarseerGames.FarseerPhysics; using FarseerGames.FarseerPhysics.Interfaces; using FarseerGames.FarseerPhysics.Dynamics; using FarseerGames.FarseerPhysics.Collisions; using FarseerGames.FarseerPhysics.Factories; namespace Serialization.Levels.LevelElements { ///Circle.cs/// Элемент уровня: ящик /// class Box:LevelElement { ////// Тестура ящика /// public Texture2D texture; ////// Масса тела /// public float Mass=10; ////// Конструктор /// public Box() : base() { } ////// Загрузка данных /// /// Начальные параметрыpublic override void LoadContent(LevelReadElement element) { texture = level.gameManager.contentManager.Load("box"); body.Add(BodyFactory.Instance.CreateRectangleBody(level.gameManager.physicsSimulator, texture.Width, texture.Height, Mass)); geom.Add(GeomFactory.Instance.CreateRectangleGeom(level.gameManager.physicsSimulator, body[0], texture.Width, texture.Height)); body[0].Position = element.Position; body[0].Rotation = element.Rotation; TypeName = element.TypeName; } /// /// Отображение данных /// /// Игровое времяpublic override void Draw(GameTime gameTime) { level.gameManager.spriteBatch.Begin(); level.gameManager.spriteBatch.Draw(texture, body[0].Position, null, Color.White, body[0].Rotation, new Vector2(texture.Width / 2, texture.Height / 2), 1, SpriteEffects.None, 0); level.gameManager.spriteBatch.End(); } } }
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.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; using FarseerGames.FarseerPhysics; using FarseerGames.FarseerPhysics.Interfaces; using FarseerGames.FarseerPhysics.Dynamics; using FarseerGames.FarseerPhysics.Collisions; using FarseerGames.FarseerPhysics.Factories; namespace Serialization.Levels.LevelElements { ///Land.cs/// Элемент уровня: круг /// class Circle:LevelElement { ////// Тестура круга /// public Texture2D texture; ////// Масса тела /// public float Mass = 2; ////// Конструктор /// public Circle() : base() { } ////// Загрузка данных /// /// Начальные параметрыpublic override void LoadContent(LevelReadElement element) { texture = level.gameManager.contentManager.Load("circle"); body.Add(BodyFactory.Instance.CreateCircleBody(level.gameManager.physicsSimulator,texture.Width/2, Mass)); geom.Add(GeomFactory.Instance.CreateCircleGeom(level.gameManager.physicsSimulator, body[0], texture.Width/2, 100)); body[0].Position = element.Position; body[0].Rotation = element.Rotation; TypeName = element.TypeName; } /// /// Отображение данных /// /// Игровое времяpublic override void Draw(GameTime gameTime) { level.gameManager.spriteBatch.Begin(); level.gameManager.spriteBatch.Draw(texture, body[0].Position, null, Color.White, body[0].Rotation, new Vector2(texture.Width / 2, texture.Height / 2), 1, SpriteEffects.None, 0); level.gameManager.spriteBatch.End(); } } }
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.Media; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; using FarseerGames.FarseerPhysics; using FarseerGames.FarseerPhysics.Interfaces; using FarseerGames.FarseerPhysics.Dynamics; using FarseerGames.FarseerPhysics.Collisions; using FarseerGames.FarseerPhysics.Factories; namespace Serialization.Levels.LevelElements { ///Весь файл проэкта./// Элемент уровня: земля /// class Land:LevelElement { ////// Тестура земли /// public Texture2D texture; ////// Масса тела /// public float Mass=1000; ////// Конструктор /// public Land() : base() { } ////// Загрузка данных /// /// Начальные параметрыpublic override void LoadContent(LevelReadElement element) { texture = level.gameManager.contentManager.Load("land"); body.Add(BodyFactory.Instance.CreateRectangleBody(level.gameManager.physicsSimulator, texture.Width, texture.Height, Mass)); geom.Add(GeomFactory.Instance.CreateRectangleGeom(level.gameManager.physicsSimulator, body[0], texture.Width, texture.Height)); body[0].Position = element.Position; body[0].Rotation = element.Rotation; body[0].IsStatic = true; TypeName = element.TypeName; } /// /// Отображение данных /// /// Игровое времяpublic override void Draw(GameTime gameTime) { level.gameManager.spriteBatch.Begin(); level.gameManager.spriteBatch.Draw(texture, body[0].Position, null, Color.White, body[0].Rotation, new Vector2(texture.Width / 2, texture.Height / 2), 1, SpriteEffects.None, 0); level.gameManager.spriteBatch.End(); } } }
Комментарии
Отправить комментарий