|
При выполнении в лабораторной работе упражнения №1 , а именно при выполнении нижеследующего кода: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using Microsoft.Xna.Framework.Graphics;
namespace Application1 { public partial class MainForm : Form { // Объявим поле графического устройства для видимости в методах GraphicsDevice device;
public MainForm() { InitializeComponent();
// Подпишемся на событие Load формы this.Load += new EventHandler(MainForm_Load);
// Попишемся на событие FormClosed формы this.FormClosed += new FormClosedEventHandler(MainForm_FormClosed); }
void MainForm_FormClosed(object sender, FormClosedEventArgs e) { // Удаляем (освобождаем) устройство device.Dispose(); // На всякий случай присваиваем ссылке на устройство значение null device = null; }
void MainForm_Load(object sender, EventArgs e) { // Создаем объект представления для настройки графического устройства PresentationParameters presentParams = new PresentationParameters(); // Настраиваем объект представления через его свойства presentParams.IsFullScreen = false; // Включаем оконный режим presentParams.BackBufferCount = 1; // Включаем задний буфер // для двойной буферизации // Переключение переднего и заднего буферов // должно осуществляться с максимальной эффективностью presentParams.SwapEffect = SwapEffect.Discard; // Устанавливаем размеры заднего буфера по клиентской области окна формы presentParams.BackBufferWidth = this.ClientSize.Width; presentParams.BackBufferHeight = this.ClientSize.Height;
// Создадим графическое устройство с заданными настройками device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware, this.Handle, presentParams); }
protected override void OnPaint(PaintEventArgs e) { device.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);
base.OnPaint(e); } } } Выбрасывается исключение: Невозможно загрузить файл или сборку "Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" или один из зависимых от них компонентов. Не удается найти указанный файл. Делаю все пунктуально. В чем может быть проблема? |
Компьютерная 2D-графика в Microsoft XNA Game Studio 3.0
Добавление управляемого объекта и механизма остановки игры
Смысл игры заключается в том, что потерпел аварию самолет и игрок должен ловить живых людей (3 объекта) и уворачиваться от неживых объектов (чемодан и горящий обломок самолета). За подобные успешные действия будут начисляться очки. Спасение осуществляется с помощью управляемого объекта - некоторой подвижной платформы, которая будет двигаться в нижней части экрана по тросу на одном уровне. Для управления платформой закрепим клавиши-стрелки клавиатуры Влево и Вправо. Приостановку игры предусмотрим по клавише Space.
Изображение платформы будет состоять из одного фрейма, т.е. применим неанимированный спрайт. Рисунок представляет собой тележку с матрацем
-
Вызовите контекстное меню для папки Textures и командой Add/Existing Item скопируйте из прилагаемого к работе каталога Source файл platform.png
-
Объявите в классе StartGame поле для адресации объекта platform и инициализируйте его созданием объекта. Для создания объекта используйте конструктор без параметров класса Sprite, поскольку platform является неанимированным спрайтом
public class StartGame : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Sprite[] sprite = new Sprite[5];
Sprite platform = new Sprite();
..........................................
}-
В методе Initialize() класса StartGame задайте начальную позицию платформы
protected override void Initialize()
{
...................................................
// Начальная позиция платформы
platform.spritePosition = new Vector2(
this.Window.ClientBounds.Width / 2,
this.Window.ClientBounds.Height - 88);
base.Initialize();
}-
В методе LoadContent() класса StartGame пропишите код загрузки рисунка платформы в объект программы
protected override void LoadContent()
{
......................................................
// Загрузка рисунка платформы в объект
platform.Load(this.Content, "Textures\\platform");
}-
В методе обновления состояния игры Update() класса StartGame вставьте вызов функции MovePlatform() перемещения платформы, а в самом основном классе определите эту функцию
KeyboardState keyboardState;
protected override void Update(GameTime gameTime)
{
....................................................
// Перемещение сверху вниз на величину speedSprite
MoveSprite();
// Перемещение платформы по экрану
MovePlatform();
base.Update(gameTime);
}
// Перемещение платформы по экрану
void MovePlatform()
{
int speedPlatform = 10;// Скорость платформы
// Проверка клавиш перемещения
if (keyboardState.IsKeyDown(Keys.Left))
platform.spritePosition.X -= speedPlatform;
else if (keyboardState.IsKeyDown(Keys.Right))
platform.spritePosition.X += speedPlatform;
// Проверка границ
int minValue = 20;
int maxValue = this.Window.ClientBounds.Width
- (platform.spriteTexture.Width + 265);
if (platform.spritePosition.X < minValue)
platform.spritePosition.X = minValue;
else if (platform.spritePosition.X > maxValue)
platform.spritePosition.X = maxValue;
}-
Вставьте в функцию Draw() класса StartGame код рисования платформы на экране. Платформу вставьте в самый верхний слой над тросом
protected override void Draw(GameTime gameTime)
{
// Очистка буфера рисования
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
spriteBatch.Draw(background1, new Vector2(0, 0), Color.White);
for (int i = 0; i < sprite.Length; i++)
sprite[i].DrawAnimationSprite(spriteBatch);
spriteBatch.Draw(background2,new Vector2(0,0),Color.White);
platform.DrawSprite(spriteBatch);// В верхний слой над тросом
spriteBatch.End();
base.Draw(gameTime);
}Для приостановки игры нужно ввести булево поле-флаг pause, состояние которого менять на противоположное при каждом нажатии закрепленной за паузой клавиши. Затем нужно охватить код движения объектов в функции Update() класса StartGame условием, которое зависит от состояния флага pause. Но такой механизм является неустойчивым в работе, поскольку извлечение клавиши, поднятие флага и проверка условия выполняются за один проход вызова функции Update(). Вот пример неустойчивого кода
KeyboardState keyboardState;
bool pause = false;
protected override void Update(GameTime gameTime)
{
// Выход из игры...
// Читать буфер клавиатуры
keyboardState = Keyboard.GetState();
// Распознать клавишу Esc
if (keyboardState.IsKeyDown(
Microsoft.Xna.Framework.Input.Keys.Escape) == true)
this.Exit();
// Отслеживание клавиши паузы и поднятие флага
if (keyboardState.IsKeyDown(Keys.Space))
paused = !paused;
// Все движение посадим на проверку условия флага паузы
if (paused == false)
{
// Смена кадров
double elapsed = gameTime.ElapsedGameTime.TotalSeconds;
for (int i = 0; i < sprite.Length; i++)
sprite[i].UpdateFrame(elapsed);
// Перемещение сверху вниз на величину speedSprite
MoveSprite();
// Перемещение платформы по экрану
MovePlatform();
}
base.Update(gameTime);
}Для устойчивой работы механизма установления паузы в игре введем два поля-флага pauseKeyDown и paused и создадим функцию Pause(), вызов которой поместим в функцию Update() класса StartGame. Если будет нажата закрепленная за паузой клавиша ( Space ), то при первом вызове функции Pause() поднимется флаг, сигнализирующий об этом, и только при следующем вызове функции будет поднят флаг самой паузы. Таким образом, установка паузы растянется на два прохода функции Update().
-
Добавьте к классу StartGame устойчивый
двухступенчатый код приостановки игры
KeyboardState keyboardState;
protected override void Update(GameTime gameTime)
{
// Выход из игры...
// Читать буфер клавиатуры
keyboardState = Keyboard.GetState();
// Распознать клавишу Esc
if (keyboardState.IsKeyDown(
Microsoft.Xna.Framework.Input.Keys.Escape) == true)
this.Exit();
// Все движение посадим на проверку условия флага паузы
Pause();// Отслеживание клавиши паузы и поднятие флага
if (paused == false)
{
// Смена кадров
double elapsed = gameTime.ElapsedGameTime.TotalSeconds;
for (int i = 0; i < sprite.Length; i++)
sprite[i].UpdateFrame(elapsed);
// Перемещение сверху вниз на величину speedSprite
MoveSprite();
// Перемещение платформы по экрану
MovePlatform();
}
base.Update(gameTime);
}
bool paused = false;// Флаг паузы в игре
bool pauseKeyDown = false;
void Pause()
{
if (keyboardState.IsKeyDown(Keys.Space) == true)
pauseKeyDown = true;
else if (pauseKeyDown == true)
{
pauseKeyDown = false;
paused = !paused;
}
}-
Перекомпилируйте проект командой Rebuild, запустите приложение и убедитесь в функционировании платформы и механизма приостановки игры
Добавление игровых столкновений
На данном этапе в нашей игре 5 объектов падают с неба в циклическом режиме. В нижней части экрана курсирует платформа, которая обязана ловить живые объекты и уворачиваться от неживых. За это будут насчитываться очки. В связи с этим необходимо добавить механизм, который бы фиксировал столкновение объекта с платформой и принимал решение о поощрении. После этого перехваченный объект будем перемещать на исходную позицию для нового движения.
В библиотеке XNA Framework детектором столкновений между объектами служит структура BoundingBox (ограничивающий прямоугольник). Этот невидимый прямоугольник подгоняется под размер каждого фрейма изображения различных спрайтов и при наложении прямоугольников этих объектов фиксируется факт столкновения экземплярным методом Intersects(). Размеры плоского прямоугольника BoundingBox определяются переменными-членами Min и Max, которые обязательно задаются трехмерной структурой Vector3 с нулевой координатой z, например
// Создаем ограничивающий прямоугольник фрейма
BoundingBox bb;
// Определяем его размер
bb.Min = new Vector3(10, 20, 0);// Левый верхний угол
bb.Max = new Vector3(60, 80, 0);// Правый нижний уголСпрайты разного размера должны иметь свои ограничивающие прамоугольники. Чем плотнее будут подогнаны ограничивающие прамоугольники к спрайтам, тем точнее будут обрабатываться столкновения между объектами. Ограничивающий прямоугольник для платформы мы специально уменьшим по высоте, чтобы столкновения выглядели более реалистичными.
-
Добавьте к основному классу игры StartGame код создания ограничивающих прямоугольников для всех объектов спрайтов в текущем положении, включая платформу, код определения столкновений и реакцию на них. Упакуйте все в метод Collisions(), который будет таким
// Текущее создание ограничивающих прямоугольников
// для всех объектов игры и реакция на столкновения
BoundingBox bbPlatform;
BoundingBox[] bbSprite = new BoundingBox[5];
void Collisions()
{
// Построение ограничивающего прямоугольника платформы
bbPlatform.Min = new Vector3(// Левый верхний угол
platform.spritePosition.X,
platform.spritePosition.Y +
platform.spriteTexture.Height / 3,// Уменьшили высоту прямоугольника
0);
bbPlatform.Max = new Vector3(// Правый нижний угол
platform.spritePosition.X + platform.spriteTexture.Width,
platform.spritePosition.Y + platform.spriteTexture.Height,
0);
// Построение ограничивающих прямоугольников летящих объектов
for (int i = 0; i < bbSprite.Length; i++)
{
bbSprite[i].Min = new Vector3(// Левый верхний угол
sprite[i].spritePosition.X,
sprite[i].spritePosition.Y,
0);
bbSprite[i].Max = new Vector3(// Правый нижний угол
sprite[i].spritePosition.X +
sprite[i].spriteTexture.Width / 12,// Ширина одного фрейма
sprite[i].spritePosition.Y +
sprite[i].spriteTexture.Height,
0);
}
// Проверка пересечений ограничивающих прямоугольников
// летящих объектов с каймой платформы и реакция на них
for (int i = 0; i < bbSprite.Length; i++)
{
if (bbPlatform.Intersects(bbSprite[i]))
{
// Сброс координат следующего прохода в начальную точку.
// То же, что в методе MoveSprite(), только по другой причине
int minValue = 10;
int maxValue = this.Window.ClientBounds.Width - 300
- sprite[i].spriteTexture.Width / 12;
sprite[i].spritePosition = new Vector2(
rand.Next(minValue, maxValue), -300);
}
}
}-
Вставьте вызов метода Collisions() для
проверки столкновений и реакции на них в конец метода Update() после кода перемещения спрайтов и платформы
KeyboardState keyboardState;
protected override void Update(GameTime gameTime)
{
// Выход из игры...
// Читать буфер клавиатуры
keyboardState = Keyboard.GetState();
// Распознать клавишу Esc
if (keyboardState.IsKeyDown(
Microsoft.Xna.Framework.Input.Keys.Escape) == true)
this.Exit();
// Все движение посадим на проверку условия флага паузы
Pause();// Отслеживание клавиши паузы и поднятие флага
if (paused == false)
{
// Смена кадров
double elapsed = gameTime.ElapsedGameTime.TotalSeconds;
for (int i = 0; i < sprite.Length; i++)
sprite[i].UpdateFrame(elapsed);
// Перемещение сверху вниз на величину speedSprite
MoveSprite();
// Перемещение платформы по экрану
MovePlatform();
// Проверка столкновений и реакция на них
Collisions();
}
base.Update(gameTime);
}-
Постройте проект и убедитесь в работоспособности механизма столкновений
Подсчет очков
Начисление очков определяется стратегией игры и ее целью. Например, за пойманные живые объекты можно начислять очки, а за пропущенные живые или пойманные неживые - уменьшать баллы или даже отнимать жизнь у игрока. Можно также ограничить время игры и вместо уменьшения баллов отнимать игровое время.
В нашей игре мы примем простую стратегию и будем учитывать очки отдельно для каждого объекта. За каждый пойманный объект, живой или неживой, будем начислять одно очко. Такая задача подсчета очков реализуется очень просто.
-
Добавьте в класс StartGame объявление поля массива целого типа scores[5] вместе с его инициализацией, а в функции столкновений Collisions() установите подсчет очков для каждого объекта
// Текущее создание ограничивающих прямоугольников
// для всех объектов игры и реакция на столкновения
BoundingBox bbPlatform;
BoundingBox[] bbSprite = new BoundingBox[5];
int[] scores = new int[5] { 0, 0, 0, 0, 0 };// Массив очков
void Collisions()
{
...............................................
// Проверка пересечений ограничивающих прямоугольников
// летящих объектов с каймой платформы и реакция на них
for (int i = 0; i < bbSprite.Length; i++)
{
if (bbPlatform.Intersects(bbSprite[i]))
{
// Сброс координат следующего прохода в начальную точку.
// То же, что в методе MoveSprite(), только по другой причине
int minValue = 10;
int maxValue = this.Window.ClientBounds.Width - 300
- sprite[i].spriteTexture.Width / 12;
sprite[i].spritePosition = new Vector2(
rand.Next(minValue, maxValue), -300);
// Подсчет очков по сумме столкновений с объектами
scores[i]++;
}
}
}

