При выполнении в лабораторной работе упражнения №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
- Дополните несколько методов класса StartGame кодом анимации, как показано в листинге
public StartGame() { ............................................ // Создание объекта //sprite = new Sprite(); // 12 кадров анимационной последовательности // показываем со скоростью 10 кадров в секунду sprite = new Sprite(12, 10); } protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); //sprite.Load(this.Content, "Textures\\sprite"); sprite.Load(this.Content, "Textures\\0"); } protected override void Update(GameTime gameTime) { ............................................ // Смена кадров double elapsed = gameTime.ElapsedGameTime.TotalSeconds; sprite.UpdateFrame(elapsed); base.Update(gameTime); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(SpriteBlendMode.AlphaBlend); //sprite.DrawSprite(spriteBatch); sprite.DrawAnimationSprite(spriteBatch); spriteBatch.End(); base.Draw(gameTime); }
- Вызовите контекстное меню для папки Textures и командой Add/Existing Item скопируйте из прилагаемого к работе каталога Source файл 0.png. Не забудьте в диалоговом окне Add Existing Item установить фильтр типа файла в значение Content Pipeline Files
- Перекомпилируйте проект командой Rebuild, запустите приложение и убедитесь, что объект совершает движение согласно следующей анимационной последовательности размером 1680x130 пикселов
Добавление фона
Пришла пора добавить в игру фон, который будет представлен двумя рисунками background1.png и background2.png. Эти рисунки в уменьшенном масштабе имеют следующий вид
Рисунок background2.png представляет собой рамку с вырезаной прозрачной серединой, за которой должен стоять рисунок background1.png. Рисунки будут располагаться каждый в своем слое. Между ними мы поместим еще один слой, в котором будет двигаться анимационный объект. Ближний к наблюдателю слой будет заслонять дальние слои, идущие в глубину экрана. Порядок расположения слоев определяется порядком формирования сцены в методе Draw() основного класса игры: вначале мы выведем background1.png, затем анимационный объект, а затем поверх все графики наложим рамку background2.png.
- Вызовите контекстное меню для папки Textures и командой Add/Existing Item скопируйте из прилагаемого к работе каталога Source файлы background1.png и background2.png
- Внесите соответствующие изменения в основной класс игры для добавления фона
public class StartGame : Microsoft.Xna.Framework.Game { protected override void Initialize() { // Для прикрепления левого верхнего // угла спрайта к центру экрана //sprite.spritePosition = new Vector2( // this.Window.ClientBounds.Width / 2, // this.Window.ClientBounds.Height / 2); // Начальная позиция объекта анимации sprite.spritePosition = new Vector2(300, 200); base.Initialize(); } Texture2D background1, background2;// Объявление ссылок на рисунки фона protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); sprite.Load(this.Content, "Textures\\0"); // Загружаем фон background1 = this.Content.Load<Texture2D>("Textures\\background1"); background2 = this.Content.Load<Texture2D>("Textures\\background2"); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(SpriteBlendMode.AlphaBlend); spriteBatch.Draw(background1, new Vector2(0, 0), Color.White); sprite.DrawAnimationSprite(spriteBatch); spriteBatch.Draw(background2, new Vector2(0, 0), Color.White); spriteBatch.End(); base.Draw(gameTime); } }
- Перекомпилируйте проект командой Rebuild, запустите приложение и убедитесь в правильности работы кода
Снимок экрана в уменьшенном виде на данном этапе будет таким
Добавление спрайту движения по экрану
Если при рисовании каждого нового кадра анимационной последовательности сдвигать позицию рисования на экране на некоторую величину, то получится иллюзия движения спрайта по экрану. Аналогичного эффекта можно добиться, если сдвигать фон, не меняя позицию спрайта.
Для нашего объекта мы будем увеличивать координату y, учитывая, что начало координат находится в левом верхнем углу экрана и ось y направлена сверху вниз. Поскольку размеры одного фрейма киноленты равны ( 1680/12x130=140x130 ), то для создания эффекта появления летящего вниз объекта начальную точку (x, y) рисования выберем за верхней границей экрана. Для первого прохода начальную точку примем с запасом (x=300, y=-200), а затем для каждого нового прохода начальное значение координаты x будем варьировать случайным образом, а начальное значение координаты y оставим прежним y=-200.
- Внесите соответствующие изменения в основной класс игры для организации вертикального перемещения спрайта по экрану сверху вниз
public class StartGame : Microsoft.Xna.Framework.Game { ............................................ protected override void Initialize() { // Начальная позиция объекта анимации //sprite.spritePosition = new Vector2(300, 200); // Начальная позиция объекта анимации при первом проходе sprite.spritePosition = new Vector2(300, -200); base.Initialize(); } ............................................ KeyboardState keyboardState; protected override void Update(GameTime gameTime) { // Выход из игры... // Читать буфер клавиатуры keyboardState = Keyboard.GetState(); // Распознать клавишу Esc if (keyboardState.IsKeyDown( Microsoft.Xna.Framework.Input.Keys.Escape) == true) this.Exit(); // Смена кадров double elapsed = gameTime.ElapsedGameTime.TotalSeconds; sprite.UpdateFrame(elapsed); // Перемещение сверху вниз на величину speedSprite MoveSprite(); base.Update(gameTime); } // Поле для случайного изменения // координаты x в начальной точке прохода Random rand = new Random(); // Функция перемещения сверху вниз на величину speedSprite void MoveSprite() { sprite.spritePosition += sprite.speedSprite; if (sprite.spritePosition.Y > this.Window.ClientBounds.Height) { // Сброс координат следующего прохода в начальную точку int minValue = 10; int maxValue = this.Window.ClientBounds.Width - 300 - sprite.spriteTexture.Width / 12; sprite.spritePosition = new Vector2( rand.Next(minValue, maxValue), -200); } } ............................................ }
public class Sprite { // Поля public Texture2D spriteTexture;// Ссылка на объект рисунка public Vector2 spritePosition; // Позиция рисования int frameCount; // Количество кадров последовательности double timeFrame; // Время показа одного фрейма на экране (задержка) int frame; // Номер показываемого фрейма double totalElapsed;// Время, прошедшее с начала показа текущего фрейма public Vector2 speedSprite = new Vector2(0, 6);// Скорость перемещения в pixels ............................................ }
- Перекомпилируйте проект командой Rebuild, запустите приложение и убедитесь в функционировании механизма вертикального перемещения спрайтов одного объекта по экрану
Добавление к игре новых объектов
Добавим к существующему объекту еще 4 новых анимационных последовательности так, чтобы всего их стало 5. Каждая из этих последовательностей имеет одинаковое количество кадров 12, хотя и разные их размеры. Для удобства програмирования эти последовательности будут иметь имена файлов от 0 до 4 и представлять следующее
- Вызовите контекстное меню для папки Textures и командой Add/Existing Item скопируйте из прилагаемого к работе каталога Source файлы 1.png, 2.png, 3.png, 4.png
Для хранения ссылок на объекты создадим массив ссылок, в который в методе LoadContent() основного класса игры загрузим рисунки. В других местах класса StartGame заменим код обработки одиночного объекта на цикл обработки многих объектов.
- Модифицируйте код класса StartGame для движения многих объектов следующим образом
public class StartGame : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; //Sprite sprite; Sprite[] sprite = new Sprite[5]; public StartGame() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; // Включается стандартный курсор мыши !!!!!!!!!!!!!!!!!!!!!!!!! // this.IsMouseVisible = true; // Установка разрешения экрана graphics.PreferredBackBufferWidth = 1024; graphics.PreferredBackBufferHeight = 768; // Переключение в полноэкранный режим graphics.ToggleFullScreen();// или graphics.IsFullScreen = true; // 12 кадров анимационной последовательности // показываем со скоростью 10 кадров в секунду //sprite = new Sprite(12, 10); for (int i = 0; i < sprite.Length; i++) sprite[i] = new Sprite(12, 10); } protected override void Initialize() { // Начальная позиция объекта анимации при первом проходе //sprite.spritePosition = new Vector2(300, -200); int distance = 0; int minValue = 10; int maxValue = this.Window.ClientBounds.Width - 300; for (int i = 0; i < sprite.Length; i++) { sprite[i].spritePosition = new Vector2(rand.Next(minValue, maxValue), distance -= 300); } base.Initialize(); } Texture2D background1, background2;// Объявление ссылок на рисунки фона protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); //sprite.Load(this.Content, "Textures\\0"); // Загрузка рисунков анимированных спрайтов for (int i = 0; i < sprite.Length; i++) { sprite[i].Load(this.Content, "Textures\\" + i.ToString()); } // Загружаем фон background1 = this.Content.Load<Texture2D>("Textures\\background1"); background2 = this.Content.Load<Texture2D>("Textures\\background2"); } protected override void UnloadContent() { // TODO: Unload any non ContentManager content here } KeyboardState keyboardState; protected override void Update(GameTime gameTime) { // Выход из игры... // Читать буфер клавиатуры keyboardState = Keyboard.GetState(); // Распознать клавишу Esc if (keyboardState.IsKeyDown(Keys.Escape) == true) this.Exit(); // Смена кадров double elapsed = gameTime.ElapsedGameTime.TotalSeconds; //sprite.UpdateFrame(elapsed); for (int i = 0; i < sprite.Length; i++) sprite[i].UpdateFrame(elapsed); // Перемещение сверху вниз на величину speedSprite MoveSprite(); base.Update(gameTime); } // Поле для случайного изменения // координаты x в начальной точке прохода Random rand = new Random(); // Функция перемещения сверху вниз на величину speedSprite void MoveSprite() { /* sprite.spritePosition += sprite.speedSprite; if (sprite.spritePosition.Y > this.Window.ClientBounds.Height) { // Сброс координат следующего прохода в начальную точку int minValue = 10; int maxValue = this.Window.ClientBounds.Width - 300 - sprite.spriteTexture.Width / 12; sprite.spritePosition = new Vector2( rand.Next(minValue, maxValue), -200); } */ for (int i = 0; i < sprite.Length; i++) { sprite[i].spritePosition += sprite[i].speedSprite; if (sprite[i].spritePosition.Y > this.Window.ClientBounds.Height) { // Сброс координат следующего прохода в начальную точку 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); } } } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(SpriteBlendMode.AlphaBlend); spriteBatch.Draw(background1, new Vector2(0, 0), Color.White); //sprite.DrawAnimationSprite(spriteBatch); for (int i = 0; i < sprite.Length; i++) sprite[i].DrawAnimationSprite(spriteBatch); spriteBatch.Draw(background2, new Vector2(0, 0), Color.White); spriteBatch.End(); base.Draw(gameTime); } }
- Перекомпилируйте проект командой Rebuild, запустите приложение и убедитесь, что все 5 объектов падают сверху вниз с установленной скоростью