|
При выполнении в лабораторной работе упражнения №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" или один из зависимых от них компонентов. Не удается найти указанный файл. Делаю все пунктуально. В чем может быть проблема? |
Компьютерная графика 3D в XNA
Добавление экранных заставок
В самом начале построения приложения мы в методах LoadContent() и Draw() с помощью оператора switch заложили несколько состояний игры, определенных в перечислении GameState
- AboutScreen, // Экран с информацией об игре
- GameOverScreen, // Экран проигрыша
- GameScreen, // Экран игрового процесса
- HelpScreen, // Инструкция о правилах
- MenuScreen, // Меню игры
- SplashScreen, // Первая игровая заставка
- VictotyScreen, // Экран выигрыша
До сих пор мы реализовали только одно из них - саму игру. В этом разделе закодируем еще три состояния: SplashScreen, AboutScreen, HelpScreen. Смену режимов закрепим за клавишами Enter и Esc.
Экран игровой заставки SplashScreen
Первой будет появляться игровая заставка, из которой по клавише Enter попадем в меню, а по клавише Esc выйдем из игры. Игровая заставка будет состоять из нескольких отдельных компонентов:
- Фоновый рисунок splash.png
- Вехний заголовок игры title.png
- Нижняя подсказка enter.png
- Изображение пулевого отверстия hole.png, которое мы разбросаем по экрану заставки случайным образом в 30 экземплярах
- Модели вращающегося мяча Soccerball.x посередине экрана на переднем плане заставки
Прежде всего нужно скопировать в проект эти компоненты заставки.
-
В панели Solution
Explorer вызовите контекстное меню для каталога проекта Textures и дабавьте
командой Add/Existing Item из прилагаемого каталога Source файлы
с рисунками splash.png, title.png, enter.png, hole.png
Код игровой заставки упакуем в класс SplashScreen.
-
Командой Project/Add Class меню
оболочки добавьте к проекту файл SplashScreen.cs и
скопируйте в него все инструкции using из файла StartGame3D
-
Заполните файл SplashScreen.cs следующим
кодом
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.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace Game3D
{
class SplashScreen
{
#region Поля класса
Texture2D splash, title, enter, hole; // Объекты рисунков
Vector2[] posHole = new Vector2[30]; // Массив позиций рисунка пули
Random rand = new Random(); // Генератор случайных чисел
ModelClass ball = new ModelClass(); // Объект мяча
float aspectRatio; // Коэффициент искажения проекции
float FOV = MathHelper.PiOver4; // Ракурс камеры 45 градусов
float nearClip = 1.0f; // Ближняя отсекающая плоскость
float farClip = 1000.0f; // Дальняя отсекающай плоскость
float angle = 0; // Угол поворота
Matrix world, view, proj; // Матрицы преобразований
#endregion
// Инициализация объектов
// content - контент экземпляра основного класса игры
// width - текущаяя ширина экрана
// height - текущая высота экрана
public void InitializeSplashScreen(ContentManager content, int width, int height)
{
// Загружаем в объекты изображения и модель мяча
splash = content.Load<Texture2D>("Textures\\splash");
title = content.Load<Texture2D>("Textures\\title");
enter = content.Load<Texture2D>("Textures\\enter");
hole = content.Load<Texture2D>("Textures\\hole");
ball.Load(content, "Models\\Soccerball");
ball.Position = new Vector3(0, 0, 0);// В центре экрана, где начало мировой системы координат
// Разбрасываем по экрану пулевые отверстия
for (int i = 0; i < posHole.Length; i++)
{
posHole[i].X = rand.Next(20, width - 60);
posHole[i].Y = rand.Next(100, height - 60);
}
// Коэффициент искажения проекции
aspectRatio = (float)width / height;
}
// Вывод заставки на экран
// spriteBatch - объект рисования спрайтов
// graphics - объект графического устройства GDI
// width - текущаяя ширина экрана
// height - текущая высота экрана
// gameTime - длительность одного такта игры
public void DrawScreen(SpriteBatch spriteBatch, GraphicsDeviceManager graphics,
int width, int height, GameTime gameTime)
{
// Очищаем экран своим цветом
graphics.GraphicsDevice.Clear(Color.DarkGreen);
// Рисуем в GDI плоские компоненты относительно центра экрана и в Z-последовательности
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
spriteBatch.Draw(splash, new Vector2(width / 2 - splash.Width / 2,
height / 2 - splash.Height / 2), Color.White);
spriteBatch.Draw(title, new Vector2(width / 2 - title.Width / 2,
30), // Чуть опустили
Color.White);
spriteBatch.Draw(enter, new Vector2(width / 2 - enter.Width / 2,
height - enter.Height - 30), // Чуть приподняли
Color.White);
for (int i = 0; i < posHole.Length; i++)
spriteBatch.Draw(hole, posHole[i], Color.White);
spriteBatch.End();
// Рисуем объемный мяч на переднем плане
graphics.GraphicsDevice.RenderState.DepthBufferEnable = true;// Включаем буфер глубины
view = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 150.0f), Vector3.Zero, Vector3.Up);
proj = Matrix.CreatePerspectiveFieldOfView(FOV, aspectRatio, nearClip, farClip);
world = Matrix.CreateTranslation(ball.Position);
angle += (float)(gameTime.ElapsedGameTime.TotalSeconds * 2.0f);// Увеличиваем угол вращения мяча
world *= Matrix.CreateRotationY(angle);
ball.DrawModel(world, view, proj);
}
}
}-
Для тестирования разработанного
класса SplashScreen введите временно следующие изменения в
основной класс игры
public class StartGame3D : Microsoft.Xna.Framework.Game
{
#region Поля класса
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
int screenWidth, screenHeight; // Размеры экрана
KeyboardState keyboardState; // Буфер клавиатуры
//GameState gameState = GameState.GameScreen; // Переменная состояния игры
GameState gameState = GameState.SplashScreen; // Переменная состояния игры
Matrix world; // Мировая матрица
Matrix view; // Матрица вида
Matrix proj; // Проекционная матрица
float aspectRatio; // Коэффициент искажения проекции
float FOV = MathHelper.PiOver4; // Ракурс
float nearClip = 1.0f; // Ближняя отсекающая плоскость перспективы
float farClip = 1000.0f; // Дальняя отсекающая плоскость перспективы
//Vector3 camera = new Vector3(0.0f, 0.0f, 150.0f);
Vector3 camera = new Vector3(0.0f, 20.0f, 250.0f);
//ModelClass ball;
ModelClass[] ball = new ModelClass[3];
MouseState mouseState;
Random rand = new Random();
// Создание объекта курсора-прицела
Game2D.Sprite cursor = new Game2D.Sprite();
// Создание объекта модели стадиона
ModelClass stadium = new ModelClass();
// Создание объекта для рисунка пейзажа
Game2D.Sprite background = new Game2D.Sprite();
// Создание объектов для других состояний экранов
SplashScreen splash = new SplashScreen();
#endregion
protected override void LoadContent()
{
....................................................
// Загружаем рисунок заднего фона
background.Load(this.Content, "Textures\\hallake001");
// Чуть приподнимем вверх экрана
background.spritePosition = new Vector2(0, -50);
// Инициализация объектов других состояний экранов
splash.InitializeSplashScreen(this.Content, screenWidth, screenHeight);
}
protected override void Update(GameTime gameTime)
{
// Читать буфер клавиатуры
keyboardState = Keyboard.GetState();
switch (gameState)
{
case GameState.AboutScreen:
break;
case GameState.GameOverScreen:
break;
case GameState.GameScreen:
// Выход из игрового процесса
if (keyboardState.IsKeyDown(Keys.Escape))
this.Exit();
MoveBalls();
MouseClick();
break;
case GameState.HelpScreen:
break;
case GameState.MenuScreen:
break;
case GameState.SplashScreen:
// Выход из игрового процесса
if (keyboardState.IsKeyDown(Keys.Escape))
this.Exit();
break;
case GameState.VictotyScreen:
break;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
switch (gameState)
{
case GameState.AboutScreen:
break;
case GameState.GameOverScreen:
break;
case GameState.GameScreen:
.......................................................
break;
case GameState.HelpScreen:
break;
case GameState.MenuScreen:
break;
case GameState.SplashScreen:
splash.DrawScreen(this.spriteBatch, this.graphics, screenWidth, screenHeight, gameTime);
break;
case GameState.VictotyScreen:
break;
}
base.Draw(gameTime);
}
}-
Запустите приложение
и убедитесь, что код класса SplashScreen работает нормально в основном
цикле игры. Получится картинка, приведенная ниже, с вращающимся в центре
мячом
Экран с информацией об игре AboutScreen
Код этой заставки мы спроектируем на основе только что созданного класса SplashScreen, внеся в него незначительные коррективы. Эти изменения будет связаны в основном с тем, что вместо одного мяча, вращающегося в центре экрана, мы введем три мяча, которые будут вращаться как и прежде - относительно оси y, и одновременно - относительно оси z. В итоге получим сложное вращение мячей в плоскости экрана относительно его центра.
-
Загрузите в папку Textures проекта
файлы изображений about.png и esc.png из прилагаемого к работе каталога Source
-
В панели Solution
Explorer сделайте копию файла SplashScreen.cs и переименуйте
ее в файл AboutScreen.cs
-
Модифицируйте файл AboutScreen.cs так,
чтобы он выглядел следующим образом
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.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace Game3D
{
class AboutScreen
{
#region Поля класса
Texture2D about, title, esc, hole; // Объекты рисунков
Vector2[] posHole = new Vector2[30]; // Массив позиций рисунка пули
Random rand = new Random(); // Генератор случайных чисел
ModelClass [] ball = new ModelClass[3]; // Объекты мячей
float aspectRatio; // Коэффициент искажения проекции
float FOV = MathHelper.PiOver4; // Ракурс камеры 45 градусов
float nearClip = 1.0f; // Ближняя отсекающая плоскость
float farClip = 1000.0f; // Дальняя отсекающай плоскость
float angle = 0; // Угол поворота
Matrix world, view, proj; // Матрицы преобразований
#endregion
// Инициализация объектов
// content - контент экземпляра основного класса игры
// width - текущаяя ширина экрана
// height - текущая высота экрана
public void InitializeSplashScreen(ContentManager content, int width, int height)
{
// Создаем объекты для мячей
for (int i = 0; i < ball.Length; i++)
ball[i] = new ModelClass();
// Загружаем в объекты изображения и модель мяча
about = content.Load<Texture2D>("Textures\\about");
title = content.Load<Texture2D>("Textures\\title");
esc = content.Load<Texture2D>("Textures\\esc");
hole = content.Load<Texture2D>("Textures\\hole");
ball[0].Load(content, "Models\\Soccerball");
ball[0].Position = new Vector3(-30, 40, -30);
ball[1].Load(content, "Models\\SoccerballGreen");
ball[1].Position = new Vector3(50, 30, -50);
ball[2].Load(content, "Models\\SoccerballRed");
ball[2].Position = new Vector3(-50, -30, 40);
// Разбрасываем по экрану пулевые отверстия
for (int i = 0; i < posHole.Length; i++)
{
posHole[i].X = rand.Next(20, width - 60);
posHole[i].Y = rand.Next(100, height - 60);
}
// Коэффициент искажения проекции
aspectRatio = (float)width / height;
}
// Вывод заставки на экран
// spriteBatch - объект рисования спрайтов
// graphics - объект графического устройства GDI
// width - текущаяя ширина экрана
// height - текущая высота экрана
// gameTime - длительность одного такта игры
public void DrawScreen(SpriteBatch spriteBatch, GraphicsDeviceManager graphics,
int width, int height, GameTime gameTime)
{
// Очищаем экран своим цветом
graphics.GraphicsDevice.Clear(Color.DarkGreen);
// Рисуем в GDI плоские компоненты относительно центра экрана и в Z-последовательности
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
spriteBatch.Draw(about, new Vector2(width / 2 - about.Width / 2,
height / 2 - about.Height / 2), Color.White);
spriteBatch.Draw(title, new Vector2(width / 2 - title.Width / 2,
30), // Чуть опустили
Color.White);
spriteBatch.Draw(esc, new Vector2(width / 2 - esc.Width / 2,
height - esc.Height - 30), // Чуть приподняли
Color.White);
for (int i = 0; i < posHole.Length; i++)
spriteBatch.Draw(hole, posHole[i], Color.White);
spriteBatch.End();
// Рисуем мячи на переднем плане
graphics.GraphicsDevice.RenderState.DepthBufferEnable = true;// Включаем буфер глубины
view = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 260.0f), Vector3.Zero, Vector3.Up);
proj = Matrix.CreatePerspectiveFieldOfView(FOV, aspectRatio, nearClip, farClip);
angle += (float)(gameTime.ElapsedGameTime.TotalSeconds * 1.0f);
Matrix rotationMatrixY = Matrix.CreateRotationY(angle);
Matrix rotationMatrixZ = Matrix.CreateRotationZ(angle);
for (int i = 0; i < ball.Length; i++)
{
world = Matrix.CreateTranslation(ball[i].Position);
ball[i].DrawModel(rotationMatrixY * world * rotationMatrixZ, view, proj);
}
}
}
}-
Для тестирования
разработанного класса AboutScreen введите временно следующие изменения
в основной класс игры
public class StartGame3D : Microsoft.Xna.Framework.Game
{
#region Поля класса
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
int screenWidth, screenHeight; // Размеры экрана
KeyboardState keyboardState; // Буфер клавиатуры
GameState gameState = GameState.AboutScreen; // Переменная состояния игры
Matrix world; // Мировая матрица
Matrix view; // Матрица вида
Matrix proj; // Проекционная матрица
float aspectRatio; // Коэффициент искажения проекции
float FOV = MathHelper.PiOver4; // Ракурс
float nearClip = 1.0f; // Ближняя отсекающая плоскость перспективы
float farClip = 1000.0f; // Дальняя отсекающая плоскость перспективы
//Vector3 camera = new Vector3(0.0f, 0.0f, 150.0f);
Vector3 camera = new Vector3(0.0f, 20.0f, 250.0f);
//ModelClass ball;
ModelClass[] ball = new ModelClass[3];
MouseState mouseState;
Random rand = new Random();
// Создание объекта курсора-прицела
Game2D.Sprite cursor = new Game2D.Sprite();
// Создание объекта модели стадиона
ModelClass stadium = new ModelClass();
// Создание объекта для рисунка пейзажа
Game2D.Sprite background = new Game2D.Sprite();
// Создание объектов для других состояний экранов
SplashScreen splash = new SplashScreen();
AboutScreen about = new AboutScreen();
#endregion
..............................................................
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
//ball.Load(this.Content, "Models\\Soccerball");
// Загружаем модели мячей
ball[0].Load(this.Content, "Models\\Soccerball");
ball[1].Load(this.Content, "Models\\SoccerballGreen");
ball[2].Load(this.Content, "Models\\SoccerballRed");
// Загружаем трехмерную модель стадиона
stadium.Load(this.Content, "Models\\stadium 1");
// Устанавливаем начальную позицию объектов
BeginPosition();
// Загружаем рисунок курсора-прицела
cursor.Load(this.Content, "Textures\\cursor");
// Загружаем рисунок заднего фона
background.Load(this.Content, "Textures\\hallake001");
// Чуть приподнимем вверх экрана
background.spritePosition = new Vector2(0, -50);
// Инициализация объектов других состояний экранов
splash.InitializeSplashScreen(this.Content, screenWidth, screenHeight);
about.InitializeSplashScreen(this.Content, screenWidth, screenHeight);
}
..............................................................
protected override void Update(GameTime gameTime)
{
// Читать буфер клавиатуры
keyboardState = Keyboard.GetState();
switch (gameState)
{
case GameState.AboutScreen:
// Выход из игрового процесса
if (keyboardState.IsKeyDown(Keys.Escape))
this.Exit();
break;
case GameState.GameOverScreen:
break;
case GameState.GameScreen:
// Выход из игрового процесса
if (keyboardState.IsKeyDown(Keys.Escape))
this.Exit();
MoveBalls();
MouseClick();
break;
case GameState.HelpScreen:
break;
case GameState.MenuScreen:
break;
case GameState.SplashScreen:
// Выход из игрового процесса
if (keyboardState.IsKeyDown(Keys.Escape))
this.Exit();
break;
case GameState.VictotyScreen:
break;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
switch (gameState)
{
case GameState.AboutScreen:
about.DrawScreen(this.spriteBatch, this.graphics, screenWidth, screenHeight, gameTime);
break;
case GameState.GameOverScreen:
break;
case GameState.GameScreen:
..............................................................
break;
case GameState.HelpScreen:
break;
case GameState.MenuScreen:
break;
case GameState.SplashScreen:
splash.DrawScreen(this.spriteBatch, this.graphics, screenWidth, screenHeight, gameTime);
break;
case GameState.VictotyScreen:
break;
}
base.Draw(gameTime);
}
..............................................................
}-
Запустите приложение
и убедитесь, что код класса AboutScreen работает нормально в основном
цикле игры. Получится картинка, приведенная ниже, с вращающимися в плоскости
экрана относительно его центра мячами

