При выполнении в лабораторной работе упражнения №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
Добавление звуковых эффектов
Звуковое сопровождение игры является ее неотъемлемым элементом и украшает игру. Прежде всего нужно приготовить все звуковые файлы. Потом загрузить их как объекты в проект игры и далее управлять средствами библиотеки XNA этими звуковыми объектами.
Для нашей игры мы добавим два звуковых эффекта. Один звук будет проигрываться в момент касания платформы и падающего объекта, второй звук запустится, когда объект упадет "в никуда".
- В проводнике решений выделите узел Content проекта и добавьте к нему командой меню Project/New Folder новую папку с именем Sound
- В проводнике решений выделите папку Sound и скопируйте в нее командой меню Project/Add Existing Item из прилагаемого к работе каталога Source файлы platform.wav и boom.wav
- Через проводник решений Solution Explorer выделите в папке Sound скопированные в проект звуковые файлы и в панели Properties установите для них атрибуты компилятора оболочки, как показано на рисунке
Код управления звуком упакуем в отдельный класс.
- В проводнике решений выделите корневой узел проекта Game2d и добавьте в проект командой Project/Add New Item меню оболочки новый класс C# с именем Sound
Поскольку звук в системе только один, то для управления им (и для тренировки) создадим статический класс. В соответствии с теорией языка C# статическом классе все поля данных и методы должны быть статическими и используется только конструктор по умолчанию.
- Заполните статический класс Sound следующим кодом
using System; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; namespace Game2D { // Перечисление enum SoundList { Platform, // Поймали Boom // Промазали } static class Sound { static SoundEffect boom; static SoundEffect platform; public static void Load(ContentManager content) { boom = content.Load<SoundEffect>("Sound\\boom"); platform = content.Load<SoundEffect>("Sound\\platform"); } // Воспроизведение звука public static void Play(SoundList sound) { switch (sound) { case SoundList.Boom: boom.Play(); break; case SoundList.Platform: platform.Play(); break; } } } }
- Вставьте использование класса Sound в соответствующие методы основного класса игры StartGame
public class StartGame : Microsoft.Xna.Framework.Game { ............................................ protected override void LoadContent() { ........................................ // Загружаем звук Sound.Load(this.Content); } // Функция перемещения сверху вниз на величину speedSprite void MoveSprite() { for (int i = 0; i < sprite.Length; i++) { sprite[i].spritePosition += sprite[i].speedSprite; if (sprite[i].spritePosition.Y > this.Window.ClientBounds.Height) { // Сброс координат следующего прохода в начальную точку ............................................... // Звукнуть плохо Sound.Play(SoundList.Boom); } } } 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]++; // Звукнуть хорошо Sound.Play(SoundList.Platform); } } } }
- Перекомпилируйте проект командой Rebuild и испытайте добавленный в игру звук
Добавление суммы очков
Добавим на табло общее количество очков, набранных игроком в текущей игре.
- Добавьте в класс StartGame поле целого типа totalScores, а в метод Collisions() подсчет суммы очков
int totalScores; void Collisions() { ................................................. // Проверка пересечений ограничивающих прямоугольников // летящих объектов с каймой платформы и реакция на них for (int i = 0; i < bbSprite.Length; i++) { if (bbPlatform.Intersects(bbSprite[i])) { .................................................... // Подсчет очков по сумме столкновений с объектами scores[i]++; totalScores++; // Звукнуть хорошо Sound.Play(SoundList.Platform); } } }
- Добавьте в метод NewGame() сброс суммы очков
// Новая игра void NewGame() { // Сброс очков for (int i = 0; i < scores.Length; i++) scores[i] = 0; totalScores = 0; // Начальные позиции объектов this.Initialize(); }
- В методе Draw() вставьте код печати суммы очков на экране
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // Рисуем меню if (menuState) { spriteBatch.Begin(SpriteBlendMode.AlphaBlend); menu.DrawMenu(spriteBatch, buttonState); mouse.DrawSprite(spriteBatch); spriteBatch.End(); } else ////////////// else //////////////// { 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);// В верхний слой над тросом // Вывод текста if (paused) { spriteBatch.DrawString(font2, "Пауза в игре!", new Vector2(350, 100), Color.Red); } int shift = 248; for (int i = 0; i < 5; i++) { spriteBatch.DrawString(font1, scores[i].ToString(), new Vector2(this.Window.ClientBounds.Width - 95, shift), Color.White); shift += 35; } // Печать суммы очков spriteBatch.DrawString(font1, "Итого: " + totalScores, new Vector2(this.Window.ClientBounds.Width - 150, shift), Color.White); spriteBatch.End(); } /////////////////// end else /////////////////// base.Draw(gameTime); }
Сохранение рекорда
Для сохранения результата победителя воспользуемся встроенными средствами Visual Studio 2008.
- Откройте окно свойств текущего проекта командой Project/Game2D Properties
- Выберите вкладку Settings и откройте таблицу параметров
- Заполните поля первой записи таблицы следующим образом
- Добавьте к функции UnloadContent() следующий код
// Для сохранения очков победителя Properties.Settings settings = new Properties.Settings(); int victoryScores = 0; protected override void UnloadContent() { // Запомнить рекорд if (victoryScores > settings.victoryScores) { settings.victoryScores = victoryScores; settings.Save(); } }
- Добавьте в конец конструктора класса игры код чтения рекорда
public StartGame() { ................................................. // Чтение рекорда victoryScores = settings.victoryScores; }
- Добавьте в функцию Collisions() код распознавания рекорда
void Collisions() { ......................................................... // Проверка пересечений ограничивающих прямоугольников // летящих объектов с каймой платформы и реакция на них for (int i = 0; i < bbSprite.Length; i++) { if (bbPlatform.Intersects(bbSprite[i])) { ...................................................... // Подсчет очков по сумме столкновений с объектами scores[i]++; totalScores++; // Обновление рекорда if (totalScores > victoryScores) victoryScores = totalScores; // Звукнуть хорошо Sound.Play(SoundList.Platform); } } }
- Добавьте в метод Draw() класса StartGame код вывода рекорда на экран монитора
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // Рисуем меню if (menuState) { spriteBatch.Begin(SpriteBlendMode.AlphaBlend); menu.DrawMenu(spriteBatch, buttonState); mouse.DrawSprite(spriteBatch); spriteBatch.End(); } else ////////////// else //////////////// { ........................................................ // Печать суммы очков spriteBatch.DrawString(font1, "Итого: " + totalScores, new Vector2(this.Window.ClientBounds.Width - 150, shift), Color.White); // Печать очков победителя spriteBatch.DrawString(font1, "Рекорд: " + victoryScores, new Vector2(this.Window.ClientBounds.Width - 175, 225), Color.White); spriteBatch.End(); } /////////////////// end else /////////////////// base.Draw(gameTime); }
- Откомпилируйте проект командой Rebuild и убедитесь в работе механизма сохранения очков победителя
Конечно, планировать игру нужно с самого начала, чтобы не пришлось на ходу перестраивать код как в известном анекдоте: "-Ты что программируешь? -А вот сейчас откомпилирую и узнаю!" Но мы шли от простого к сложному, постепенно наращивая код, и нам была важнее - практика программирования, а не планирование (и даже не сама игра).
Мы познакомились с основными этапами построения игрового приложения и дальнейшее усложнение игры становится рутинной работой. Поэтому остановимся на этом и рассмотрим завершающий этап - формирование инсталляционного пакета, чтобы можно было профессионально распространять наш продукт.