При выполнении в лабораторной работе упражнения №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
Добавление игрового меню
Игровое меню создадим в виде стартовой страницы приложения, с которой пользователь попадает в основной процесс. На заставке экрана меню мы нарисуем две дощечки с надписями Игра и Выход, имитирующие стандартные кнопки. Переключение фокуса между кнопками закрепим за клавишами "Стрелка вверх" и "Стрелка вниз" . Надпись на неактивной кнопке будем подкрашивать желтым цветом, а активную кнопку будем сдвигать влево на 50 пикселов.
Появление меню на экране будем регулировать флагом menuState, который изначально при запуске приложения будет поднят, а при входе в игру мы его сбросим. За переходом между кнопками меню будем следить с помощью целой переменной buttonState: значение 1 - фокус на кнопке Игра, значение 2 - фокус на кнопке Выход. Клавиша Enter будет активизировать команду текущей кнопки. Клавиша Esc будет вызывать меню из процесса игры.
Для описания игрового меню создадим отдельный класс с именем Menu. С помощью этого класса нужно будет загрузить в игру общий фон меню и на этом фоне нарисовать две кнопки с надписями.
- Вызовите в проводнике решений Solution Explorer контекстное меню для узла проекта с именем Game2D и командой Add/New Item добавьте к проекту новый класс с именем Menu
- Скопируйте из файла StartGame.cs все инструкции using и замените ими инструкции using в файле Menu.cs
- Отредактируйте класс Menu следующим образом
class Menu { // Закрытые поля-ссылки на рисунки Texture2D menuTexture; // Заставка меню public Texture2D buttonGame; // Кнопка входа в игру public Texture2D buttonExit; // Кнопка выхода из приложения // Закрытые поля-ссылки на координаты Vector2 menuPosition, buttonGamePosition, buttonExitPosition; // Свойства public Vector2 ButtonGamePosition { get { return buttonGamePosition; } set { buttonGamePosition = value; } } public Vector2 ButtonExitPosition { get { return buttonExitPosition; } set { buttonExitPosition = value; } } // Конструктор public Menu() { menuPosition = new Vector2(0, 0); buttonGamePosition = new Vector2(650, 400); buttonExitPosition = new Vector2(700, 550); } // Загрузка рисунков public void Load(ContentManager content) { menuTexture = content.Load<Texture2D>("Textures\\menu"); buttonGame = content.Load<Texture2D>("Textures\\buttonGame"); buttonExit = content.Load<Texture2D>("Textures\\buttonExit"); } // Вывод на экран public void DrawMenu(SpriteBatch spriteBatch, int buttonState) { spriteBatch.Draw(menuTexture, menuPosition, Color.White); switch (buttonState) { case 1: spriteBatch.Draw(buttonGame, buttonGamePosition, Color.White); spriteBatch.Draw(buttonExit, buttonExitPosition, Color.Yellow); break; case 2: spriteBatch.Draw(buttonGame, buttonGamePosition, Color.Yellow); spriteBatch.Draw(buttonExit, buttonExitPosition, Color.White); break; } } }
- Выделите в проводнике решений узел Textures и командой Add/Existing Item скопируйте в проект из прилагаемого каталога Source файлы с рисунками menu, buttonGame, buttonExit
Подключим класс Menu к основному классу игры StartGame.
- Объявите и инициализируйте в начале класса StartGame три поля следующим образом
public class StartGame : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Sprite[] sprite = new Sprite[5]; Sprite platform = new Sprite(); //Для хранения шрифтов SpriteFont font1, font2; // Для управления меню Menu menu = new Menu(); bool menuState = true; int buttonState = 1; ............................................... }
- Добавьте в конец метода LoadContent() код загрузки рисунков меню
protected override void LoadContent() { ................................................ // Загрузка спрайтов шрифтов font1 = this.Content.Load<SpriteFont>("Fonts\\font1"); font2 = this.Content.Load<SpriteFont>("Fonts\\font2"); // Загрузка спрайтов меню menu.Load(this.Content); }
- В метод Update() класса StartGame вставьте код, организующий логику управления меню в зависимости от нажатия закрепленных клавиш и состояния флагов
KeyboardState keyboardState; protected override void Update(GameTime gameTime) { // Выход из игры... // Читать буфер клавиатуры keyboardState = Keyboard.GetState(); // Выход в меню из игрового процесса if (keyboardState.IsKeyDown(Keys.Escape)) menuState = true; // Показываем меню if (menuState) ///////////// if ///////////// { // Отслеживаем управление клавиатурой if (keyboardState.IsKeyDown(Keys.Up)) { buttonState = 1; menu.ButtonGamePosition = new Vector2(650, 400); menu.ButtonExitPosition = new Vector2(700, 550); } else if (keyboardState.IsKeyDown(Keys.Down)) { buttonState = 2; menu.ButtonGamePosition = new Vector2(700, 400); menu.ButtonExitPosition = new Vector2(650, 550); } // Распознаем клавишу Enter для новой игры if (buttonState == 1 && keyboardState.IsKeyDown(Keys.Enter)) { this.NewGame(); menuState = false; } // Распознаем клавишу Enter для завершения приложения else if (buttonState == 2 && keyboardState.IsKeyDown(Keys.Enter)) { this.Exit(); } } //////////// end if //////////// // Игровой процесс else { ///////////// else ///////////// // Все движение посадим на проверку условия флага паузы 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(); } } /////////// end else /////////// base.Update(gameTime); } // Новая игра void NewGame() { // Сброс очков for (int i = 0; i < scores.Length; i++) scores[i] = 0; // Начальные позиции объектов this.Initialize(); }
- Откорректируйте функцию Draw(), которая в зависимости от состояния флага menuState будет рисовать либо меню, либо объекты игры
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // Рисуем меню if (menuState) { spriteBatch.Begin(SpriteBlendMode.AlphaBlend); menu.DrawMenu(spriteBatch, buttonState); // Рисует меню 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, "Pause", 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.End(); } /////////////////// end else /////////////////// base.Draw(gameTime); }
- Откомпилируйте проект в проводнике решений Solution Explorer через контекстное меню для узла проекта Game2D командой Rebuild, запустите игру и убедитесь в ее работоспособности
Добавление управления мышью
Задействуем механизм работы с мышью, с помошью которого мы будем выбирать опции в игровом меню. Прежде всего необходимо добавить графическое изображение курсора. Затем в отдельном методе организуем получение координат курсора, слежение за пересечением ограничивающих прямоугольников курсора и кнопок меню, а также обработку нажатия левой кнопки мыши.
Код предыдущего раздела, касающийся выбора пунктов меню с помощью клавиатуры, можно полностью удалить, тогда пользователь запуском игры и выходом из нее будет управлять только мышью. Но если ничего не удалять, то будет возможность использовать параллельно клавиатуру и мышь. Удалять механизм запуска игры с клавиатуры не будем.
- Через проводник решений добавьте в узел Textures спрайт с изображением курсора и именем mouse из прилагаемого к работе каталога Source
- Добавьте в класс StartGame поля-ссылки на объекты, связанные с механизмом работы мыши
public class StartGame : Microsoft.Xna.Framework.Game { ............................................... // Для управления меню с помощью мыши Sprite mouse = new Sprite();// Объект изображения курсора MouseState mouseState; // Структура состояния мыши (нажатие кнопок, координаты,...) BoundingBox bbMouse; // Структура граничивающего прямоугольника курсора BoundingBox bbButtonGame; // Структура ограничивающего прямоугольника верхней кнопки меню BoundingBox bbButtonExit; // Структура ограничивающего прямоугольника нижней кнопки меню ............................................... }
- Добавьте в метод LoadContent() класса StartGame загрузку спрайта в объект
protected override void LoadContent() { .................................................. // Загрузка спрайта курсора мыши mouse.Load(this.Content, "Textures\\mouse"); }
Код управления мышью мы упакуем в классе StartGame в отдельный метод с именем UpdateMouse(), в котором будем определять координаты курсора, фиксировать факт пересечения ограничивающих прямоугольников курсора и кнопок меню и определять при этом состояние левой кнопки мыши.
- Добавьте в класс StartGame следующую функцию с именем UpdateMouse()
// Функция управления с помощью мыши void UpdateMouse() { // Читаем координаты мыши mouseState = Mouse.GetState(); // Присваиваем координаты мыши левому верхнему углу спрайта курсора mouse.spritePosition = new Vector2(mouseState.X, mouseState.Y); // Создаем ограничивающий прямоугольник для курсора // размером 1x1 пиксел на конце стрелы bbMouse.Min = new Vector3(mouse.spritePosition.X, mouse.spritePosition.Y, 0); bbMouse.Max = new Vector3(mouse.spritePosition.X + 1, mouse.spritePosition.Y + 1, 0); // Создаем ограничивающие прямоугольники для кнопок меню bbButtonGame.Min = new Vector3(menu.ButtonGamePosition.X, menu.ButtonGamePosition.Y, 0); bbButtonGame.Max = new Vector3(menu.ButtonGamePosition.X + menu.buttonGame.Width, menu.ButtonGamePosition.Y + menu.buttonGame.Height, 0); bbButtonExit.Min = new Vector3(menu.ButtonExitPosition.X, menu.ButtonExitPosition.Y, 0); bbButtonExit.Max = new Vector3(menu.ButtonExitPosition.X + menu.buttonExit.Width, menu.ButtonExitPosition.Y + menu.buttonExit.Height, 0); // Обрабатываем пересечение ограничивающих прямоугольников if (bbMouse.Intersects(bbButtonGame)) { buttonState = 1; menu.ButtonGamePosition = new Vector2(650, 400); menu.ButtonExitPosition = new Vector2(700, 550); } if (bbMouse.Intersects(bbButtonExit)) { buttonState = 2; menu.ButtonGamePosition = new Vector2(700, 400); menu.ButtonExitPosition = new Vector2(650, 550); } // Распознаем нажатие левой кнопки мыши if (mouseState.LeftButton == ButtonState.Pressed && bbMouse.Intersects(bbButtonGame)) { this.NewGame(); menuState = false; } else if (mouseState.LeftButton == ButtonState.Pressed && bbMouse.Intersects(bbButtonExit)) { this.Exit(); } }
- Вставьте вызов функции UpdateMouse() в функцию Update() основного класса StartGame
protected override void Update(GameTime gameTime) { // Выход из игры... // Читать буфер клавиатуры keyboardState = Keyboard.GetState(); // Выход в меню из игрового процесса if (keyboardState.IsKeyDown(Keys.Escape)) menuState = true; // Показываем меню if (menuState) { // Отслеживаем управление мышью UpdateMouse(); // Отслеживаем управление клавиатурой ........................................ } // Игровой процесс else { ........................................ } base.Update(gameTime); }
- Откорректируйте функцию Draw(), которая в состоянии флага menuState=true кроме рисования меню будет рисовать и курсор мыши
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 { ........................................... } base.Draw(gameTime); }
- Откомпилируйте процесс в проводнике решений Solution Explorer через контекстное меню для узла проекта Game2D командой Rebuild, запустите игру и убедитесь в ее работоспособности