Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить..... |
Опубликован: 10.04.2009 | Доступ: свободный | Студентов: 3247 / 243 | Оценка: 4.49 / 4.39 | Длительность: 17:21:00
Темы: Компьютерная графика, Программирование, Игры
Специальности: Программист
Теги:
Самостоятельная работа 11:
Организация многоуровневых игр, конструктор уровней
Рассмотрим коды классов, которые используются в игре.
В листинге 15.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; namespace P11_1 { public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; //Текстуры Texture2D txtBack, txtBrick1, txtBrick2, txtBat, txtBall; Texture2D txtBrBuild1, txtBrBuild2, txtBrBuild0; //Массивы для хранения данных об уровнях public byte[,] Layer1, Layer2, Layer3, UserLayer; //Прямоугольник для фона Rectangle recBack = new Rectangle(0, 0, 512, 640); //Прямоугольник для "блока" Rectangle recBrick = new Rectangle(0, 0, 64, 16); //Прямоугольник для "мяча" Rectangle recBall = new Rectangle(0, 0, 10, 10); //Прямоугольник для биты Rectangle recBat = new Rectangle(0, 0, 96, 16); //Номер текущего уровня //1 - первый //2 - второй //3 - третий //-1 - пользовательский int currentLayer; //Установлена в false, если программа находится в //режиме игры, при установке в True включается //режим конструктора bool IsBuild; //Позиция указателя в режиме конструктора Vector2 PositionBuild; //Тип блока, который будет добавлен на игровое поле //при нажатии соответствующей клавиши в режиме //конструктора byte typeOfBuildBlock; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void Initialize() { //Программа находится в игровом режиме IsBuild = false; //Позиция для указателя в режиме конструктора (0,0) PositionBuild = new Vector2(0, 0); //Тип блока по умолчанию в режиме конструктора - 1 typeOfBuildBlock = 1; //пользовательский уровень по умолчанию пуст - ячейки //заполнены нулями UserLayer = new byte[40, 8]; //Заполняем массивы для разных уровней //0 - пустая ячейка //1 - блок первого типа (уничтожимый) //2 - блок второго типа (неуничтожимый) Layer1 = new byte[40, 8]{ {1,1,1,1,1,1,1,1}, {0,1,0,1,0,1,0,1}, {1,0,1,0,1,0,1,0}, {0,1,0,1,0,1,0,1}, {1,0,1,0,1,0,1,0}, {0,1,0,1,0,1,0,1}, {0,0,0,0,0,0,0,0}, {2,0,0,2,0,0,2,0}, {0,1,0,0,0,0,0,1}, {0,0,1,0,0,0,1,0}, {0,0,0,1,0,1,0,0}, {0,0,0,0,1,0,0,0}, {1,1,1,1,1,1,1,1}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0} }; Layer2 = new byte[40, 8]{ {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,1,2,1,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0} }; Layer3 = new byte[40, 8]{ {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,1,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,1,0,1,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,2,0,1,0,2,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,1,0,0,0,1,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0} }; //Текущий уровень - 1 currentLayer = 1; //Устанавливаем разрешение игрового окна //640х512 graphics.PreferredBackBufferWidth = 512; graphics.PreferredBackBufferHeight = 640; graphics.ApplyChanges(); base.Initialize(); } /// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { // Загружаем ресурсы spriteBatch = new SpriteBatch(GraphicsDevice); Services.AddService(typeof(SpriteBatch), spriteBatch); txtBack = Content.Load<Texture2D>("Back"); txtBrick1 = Content.Load<Texture2D>("Brick1"); txtBrick2 = Content.Load<Texture2D>("Brick2"); txtBall = Content.Load<Texture2D>("Ball"); txtBat = Content.Load<Texture2D>("Bat"); txtBrBuild0 = Content.Load<Texture2D>("BrickBuild0"); txtBrBuild1 = Content.Load<Texture2D>("BrickBuild1"); txtBrBuild2 = Content.Load<Texture2D>("BrickBuild2"); //Создаем уровень AddSprites(Layer1); //Добавляем биту и мяч addBallAndBAts(); } //Процедура создания уровня //расставляет элементы в соответствии с //массивом void AddSprites(byte [,] RenderLayer) { //Просматриваем массив for (int i = 0; i < 40; i++) { for (int j = 0; j < 8; j++) { if (RenderLayer[i, j] == 1) Components.Add(new Brick1(this, ref txtBrick1, new Vector2(j, i), recBrick, 64, 16)); if (RenderLayer[i, j] == 2) Components.Add(new Brick2(this, ref txtBrick2, new Vector2(j, i), recBrick, 64, 16)); } } } //Процедура для установки биты и мяча void addBallAndBAts() { Components.Add(new Ball(this, ref txtBall, new Vector2(300, 550), recBall, 1, 1)); Components.Add(new Bat(this, ref txtBat, new Vector2(300, (640 - 16)), recBat, 1, 1)); } protected override void UnloadContent() { // TODO: Unload any non ContentManager content here } protected override void Update(GameTime gameTime) { //получим состояние клавиатуры KeyboardState kb = Keyboard.GetState(); //если IsBuild = false и нажата клавиша A //переходим в режим конструктора уровней if (kb.IsKeyDown (Keys .A)&!IsBuild) { IsBuild = true; builder(); } //Если находимся в режиме конструктора уровней if (IsBuild) { //При нажатой клавише "вверх" уменьшить текущую позицию Y //указателя на 1 если позиция больше 0 if (kb.IsKeyDown(Keys.Up)) { if (PositionBuild.Y > 0) PositionBuild.Y--; } //При нажатой клавише "вниз" увеличить позицию //Y если она меньше 39 if (kb.IsKeyDown(Keys.Down)) { if (PositionBuild.Y < 39) PositionBuild.Y++; } //При нажатой клавише "влево" //уменьшить позицию X если текущая позиция //больше 0 if (kb.IsKeyDown(Keys.Left)) { if (PositionBuild.X >0) PositionBuild.X--; } //При нажатой клавише "вправо" //увеличить позицию X если текущая позиция //меньше 7 if (kb.IsKeyDown(Keys.Right)) { if (PositionBuild.X < 7) PositionBuild.X++; } //Нажатие клавиши Z устанавливает тип блока в 0 //этот блок предназначен для "стирания" //других блоков, то есть - для установки элемента //массива, соответствующего текущему состоянию //конструируемого уровня, в 0 if (kb.IsKeyDown(Keys.Z)) { typeOfBuildBlock = 0; } //При нажатии клавиши X установим 1-й тип блока if (kb.IsKeyDown(Keys.X)) { typeOfBuildBlock = 1; } //При нажатии клавиши С установим 2-й тип блока if (kb.IsKeyDown(Keys.C)) { typeOfBuildBlock = 2; } //При нажатии клавиши W запишем в //ячейку массива, соответствующую позиции указателя //текущий тип блока if (kb.IsKeyDown (Keys .W )) { UserLayer[(int)PositionBuild.Y, (int)PositionBuild.X] = typeOfBuildBlock; } //очищаем массив компонентов Components.Clear(); //выводим пользовательский уровень AddSprites(UserLayer); //уничтожаем указатель и изменяем его в соответствии с типом выбранного блока BrickBuilder br = null; if (typeOfBuildBlock == 1) br = new BrickBuilder(this, ref txtBrBuild1, PositionBuild, recBrick, 64, 16); if (typeOfBuildBlock == 2) br = new BrickBuilder(this, ref txtBrBuild2, PositionBuild, recBrick, 64, 16); if (typeOfBuildBlock == 0) br = new BrickBuilder(this, ref txtBrBuild0, PositionBuild, recBrick, 64, 16); Components.Add(br); //При нажатии клавиши W //отключаем режим конструктора //выводим пользовательский уровень //и начинаем игру if (kb.IsKeyDown(Keys.E)) { IsBuild = false; Components.Clear(); AddSprites(UserLayer); addBallAndBAts(); currentLayer = -1; } } //Если находимся в режиме игры //проверим - завершен ли текущий уровень //признак завершения уровня if (!IsBuild) { IsLayerCompleted(); } base.Update(gameTime); } //Процедура старта конструктора уровней //очищаем набор компонентов //Создаем и выводим указатель public void builder() { Components.Clear(); BrickBuilder br = new BrickBuilder (this, ref txtBrBuild1,PositionBuild, recBrick, 64, 16); Components.Add(br); } //Процедура проверки на завершенность //текущего уровня //Если на поле отсутствует мяч - игра начинается сначала //если на поле нет ни одного блока типа Brick1 - //переход на следующий уровень или переход на первый уровень //с выводом надписи "Вы выиграли" public void IsLayerCompleted() { //Предположим, что на поле нет ни одного блока //типа Brick1 bool f = false; //Предположим, что на поле нет мяча bool Ball = false; foreach (gBaseClass spr in this.Components) { //Если найден хотя бы один блок типа 1 //установим F в True if (spr.GetType() == (typeof(Brick1))) { f = true; } //Если найден мяч - установим Ball в True if (spr.GetType() == (typeof(Ball))) { Ball = true; } } //Если мяч не обнаружен //игра начинается сначала if (!Ball) { Components.Clear(); currentLayer = 1; AddSprites(Layer1); addBallAndBAts(); } //иначе else { //Если не было найдено ни одного блока //типа Brick1 if (!f) { //Очистим набор компонентов Components.Clear(); //Увеличим номер уровня currentLayer++; //в зависимости от номера //запустим соответствующий уровень if (currentLayer == 2) { AddSprites(Layer2); addBallAndBAts(); } if (currentLayer == 3) { AddSprites(Layer3); addBallAndBAts(); } //4 - если был пройден 3-й уровень //0 - при прохождении пользовательского уровня if (currentLayer == 4 | currentLayer == 0) { currentLayer = 1; AddSprites(Layer1); addBallAndBAts(); this.Window.Title = "Вы выиграли!"; } } } } protected override void Draw(GameTime gameTime) { spriteBatch.Begin(); //выведем фоновое изображение spriteBatch.Draw(txtBack, recBack, Color.White); //Выведем игровые объекты base.Draw(gameTime); spriteBatch.End(); } } }Листинг 15.1. Код класса Game1
В листинге 15.2. приведен код класса gBaseClass.
using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; using Microsoft.Xna.Framework.Content; namespace P11_1 { public class gBaseClass : Microsoft.Xna.Framework.DrawableGameComponent { Texture2D sprTexture; public Vector2 sprPosition; public Rectangle sprRectangle; public gBaseClass(Game game, ref Texture2D _sprTexture, Vector2 _sprPosition, Rectangle _sprRectangle, int X_Coord, int Y_Coord) : base(game) { sprTexture = _sprTexture; //Здесь производится перевод индекса элемента массива //в координаты на игровом экране //Так как спрайты имеют различные размеры, для их размещения на экране //используются коэффициенты X_Coord и Y_Coord sprPosition.X = _sprPosition.X * X_Coord; sprPosition.Y = _sprPosition.Y * Y_Coord; sprRectangle = _sprRectangle; } public override void Draw(GameTime gameTime) { SpriteBatch sprBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch)); sprBatch.Draw(sprTexture, sprPosition, Color.White); base.Draw(gameTime); } } }Листинг 15.2. Код класса gBaseClass
В листинге 15.3. приведен код класса Bat. Он занимается обработкой перемещений биты по горизонтали и контролем за пересечением битой левой и правой границ экрана.
using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; using Microsoft.Xna.Framework.Content; namespace P11_1 { public class Bat : gBaseClass { Rectangle scrBounds; //True для движения биты влево и False - вправо public bool direction; public Bat(Game game, ref Texture2D _sprTexture, Vector2 _sprPosition, Rectangle _sprRectangle, int x_c, int y_c) : base(game, ref _sprTexture, _sprPosition, _sprRectangle, x_c, y_c) { scrBounds = new Rectangle(0, 0, game.Window.ClientBounds.Width, game.Window.ClientBounds.Height); direction = true; } public override void Update(GameTime gameTime) { //Нажатия клавиш-стрелок влево и вправо //вызывают перемещение объекта в соответствующем //направлении KeyboardState kb = Keyboard.GetState(); if (kb.IsKeyDown(Keys.Left)) { sprPosition.X -= 2; direction = true; } if (kb.IsKeyDown(Keys.Right)) { sprPosition.X += 2; direction = false; } //проверка на столкновение с границами экрана Check(); base.Update(gameTime); } //Процедура проверки столкновения с левой //и правой границами экрана void Check() { if (sprPosition.X < scrBounds.Left) { sprPosition.X = scrBounds.Left; } if (sprPosition.X > scrBounds.Width - sprRectangle.Width) { sprPosition.X = scrBounds.Width - sprRectangle.Width; } } } }Листинг 15.3. Код класса Bat