| исключение в лабораторной работе № 3 |
Компьютерная графика 3D в XNA
Добавление меню
Для формирования заставки с элементами меню создадим игровой класс MenuScreen. Меню будет содержать фоновую заставку, титульный заголовок, подсказку действий пользователя по выбору вариантов и аналоги кнопок выбора команд. Как и в двух предыдущих заставках оставим три мяча, вращающихся относительно центра в плоскости экрана.
В центре экрана разместим команды:
- Игра - режим GameScreen
- Помощь - режим HelpScreen
- О программе - режим AboutScreen
- Выход - завершение работы
Каждую команду будем представлять текстовой надписью, под которую будем подкладывать желтый прямоугольник, если она имеет фокус ввода. Для этого придется подключить кириллический шрифт требуемого размера и гарнитуры. По краям экрана для украшательства разместим фигуры ' girl ' свободного поведения. И еще уберем отображение пуль.
-
Добавьте из
прилагаемого к работе каталога Source в папку Textures проекта файлы menu.jpg, cursorMenu.png, girlLeft.png, girlRight.png
-
Добавьте к папке Content подпапку Fonts
-
Добавьте в папку Fonts файл font.spritefont
-
Откорректируйте файл font.spritefont следующим
образом
<?xml version="1.0" encoding="utf-8"?>
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<FontName>Arial</FontName>
<Size>24</Size>
<Spacing>0</Spacing>
<UseKerning>true</UseKerning>
<Style>Bold</Style>
<CharacterRegions>
<CharacterRegion>
<Start> </Start>
<End>~</End>
</CharacterRegion>
<CharacterRegion>
<Start>А</Start>
<End>я</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>-
Скопируйте файл HelpScreen.cs и
назовите копию MenuScreen.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
{
// Объявление состояний меню
enum MenuState
{
Game, // Меню установлено на первой позиции
Help,
About,
Esc
}
class MenuScreen
{
#region Поля класса
// Объекты рисунков
Texture2D menu, title, enter, cursorMenu, girlLeft, girlRight;
// Объекты мячей
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; // Матрицы преобразований
SpriteFont font; // Для загрузки шрифта Arial 24 Bold
String[] menuCommant = { // Команды меню
"Игра",
"Помощь",
"О программе",
"Выход"
};
#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();
// Загружаем в объекты изображения и модели мячей
menu = content.Load<Texture2D>("Textures\\menu");
cursorMenu = content.Load<Texture2D>("Textures\\cursorMenu");
title = content.Load<Texture2D>("Textures\\title");
enter = content.Load<Texture2D>("Textures\\enter");
girlLeft = content.Load<Texture2D>("Textures\\girlLeft");
girlRight = content.Load<Texture2D>("Textures\\girlRight");
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);
// Коэффициент искажения проекции
aspectRatio = (float)width / height;
// Загружаем шрифт
font = content.Load<SpriteFont>("Fonts\\font");
}
// Вывод заставки на экран
// spriteBatch - объект рисования спрайтов
// graphics - объект графического устройства GDI
// width - текущаяя ширина экрана
// height - текущая высота экрана
// gameTime - длительность одного такта игры
public void DrawScreen(SpriteBatch spriteBatch, GraphicsDeviceManager graphics,
int width, int height, GameTime gameTime, int menuState)
{
// Очищаем экран своим цветом
graphics.GraphicsDevice.Clear(Color.DarkGreen);
// Рисуем в GDI плоские компоненты относительно центра экрана и в Z-последовательности
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
spriteBatch.Draw(menu, new Vector2(width / 2 - menu.Width / 2,
height / 2 - menu.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);
// Рисуем girls
spriteBatch.Draw(girlLeft, new Vector2(
0, height / 2 - girlLeft.Height / 2), Color.White);
spriteBatch.Draw(girlRight, new Vector2(
width - girlRight.Width, height / 2 - girlRight.Height / 2), Color.White);
spriteBatch.End();
// Рисуем мячи
graphics.GraphicsDevice.RenderState.DepthBufferEnable = true;// Включаем буфер глубины
view = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 250.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);
}
// Рисуем надписи меню и фон
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
int posX=width / 2 + width / 7;
int posY= height / 2;
int shift = 50;
spriteBatch.Draw(cursorMenu,
new Vector2(posX - 7, posY + shift * menuState),
Color.White);
for (int i = 0; i < menuCommant.Length; i++)
{
spriteBatch.DrawString(font,
menuCommant[i],
new Vector2(posX, posY),
Color.Red);
posY += shift;
}
spriteBatch.End();
}
}
}Обратите внимание, что расчет координат вывода графических компонентов мы ведем относительно центра экрана с учетом текущих значений его ширины и высоты. Разрешение экрана у разных пользователях может отличаться, а такой подход позволяет сохранить компоновку графических элементов на экране при разном разрешении. Для этого мы сами жестко и не устанавливаем размеры экрана, а пользуемся текущими настройками.
-
Для тестирования разработанного
класса MenuScreen введите временно следующие изменения в основной
класс игры
public class StartGame3D : Microsoft.Xna.Framework.Game
{
#region Поля класса
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
int screenWidth, screenHeight; // Размеры экрана
KeyboardState keyboardState; // Буфер клавиатуры
GameState gameState = GameState.MenuScreen; // Переменная состояния игры
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();
HelpScreen help = new HelpScreen();
MenuScreen menu = new MenuScreen();
int menuState = (int)MenuState.Game;
#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);
help.InitializeSplashScreen(this.Content, screenWidth, screenHeight);
menu.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:
// Выход из игрового процесса
if (keyboardState.IsKeyDown(Keys.Escape))
this.Exit();
break;
case GameState.MenuScreen:
// Выход из игрового процесса
if (keyboardState.IsKeyDown(Keys.Escape))
this.Exit();
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:
help.DrawScreen(this.spriteBatch, this.graphics, screenWidth, screenHeight, gameTime);
break;
case GameState.MenuScreen:
menu.DrawScreen(
this.spriteBatch, this.graphics, screenWidth, screenHeight, gameTime, menuState);
break;
case GameState.SplashScreen:
splash.DrawScreen(this.spriteBatch, this.graphics, screenWidth, screenHeight, gameTime);
break;
case GameState.VictotyScreen:
break;
}
base.Draw(gameTime);
}
}-
Запустите приложение
и убедитесь, что код класса MenuScreen работает нормально в основном
цикле игры. Должна получиться примерно такая картинка

