|
Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить..... |
Опубликован: 10.04.2009 | Уровень: специалист | Доступ: свободно
Самостоятельная работа 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