| Невозможно пройти тесты, в окне с вопросами пусто |
Пользовательский интерфейс в XNA
Этот класс использует класс Menu (листинг 20.4.), основная цель которого – удобное представление данных об отдельных пунктах меню, которых, в нашем случае, три.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace P14_1
{
//Класс для хранения данных об элементах меню
public class Menu
{
public Texture2D imageTexture;
public Rectangle imageRectangle;
public Color color;
public Menu(Game game, Texture2D _texture, Rectangle _rectangle, Color _color)
{
imageTexture = _texture;
imageRectangle = _rectangle;
color = _color;
}
}
}
Листинг
20.4.
Код класса Menu
Здесь мы лишь храним данные по отдельным элементам меню.
Экран меню вы можете видеть на рис. 20.3.
Экран справки реализован в виде класса HelpScreen, листинг 20.5. Здесь мы выводим фоновое изображение и надпись, выполненную графическими средствами.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace P14_1
{
class HelpScreen: Screen
{
//Текстуры для фона и справочной надписи
Texture2D backTexture;
Rectangle backRectangle;
Texture2D helpTexture;
Rectangle helpRectangle;
public HelpScreen(Game game, Texture2D _back, Texture2D _help, Rectangle _backRec, Rectangle _helpRec)
: base(game)
{
backTexture = _back;
helpTexture = _help;
backRectangle = _backRec;
helpRectangle = _helpRec;
}
public override void Draw(GameTime gameTime)
{
//Выводим изображения
sprBatch.Draw(backTexture, backRectangle, Color.White);
sprBatch.Draw(helpTexture, helpRectangle, Color.White);
base.Draw(gameTime);
}
}
}
Листинг
20.5.
Код класса HelpScreen
Экран справки вы можете видеть на рис. 20.4.
Основная игровая программа реализована в классе GameScreen, листинг 20.6.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input.Touch;
namespace P14_1
{
class GameScreen: Screen
{
private Texture2D sprTexture;
private Rectangle sprRectangle;
private Vector2 sprPosition;
public GameScreen(Game game, ref Texture2D newTexture,
Rectangle newRectangle, Vector2 newPosition)
: base(game)
{
sprTexture = newTexture;
sprRectangle = newRectangle;
sprPosition = newPosition;
}
public override void Update(GameTime gameTime)
{
//Обработаем касание
TouchCollection touchLocations = TouchPanel.GetState();
foreach (TouchLocation touchLocation in touchLocations)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
sprPosition = touchLocation.Position;
}
}
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
sprBatch.Draw(sprTexture, sprPosition, sprRectangle, Color.White);
base.Draw(gameTime);
}
}
}
Листинг
20.6.
Код класса GameScreen
Игровой процесс реализован здесь лишь формально – игровой объект перемещается по экрану в соответствии с позицией, которой коснулся пользователь. Игровой экран вы можете видеть на рис. 20.5.
Управление игровыми объектами, обработка ввода для целей перемещения между экранами, реализована в классе Game1, листинг 20.7.
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
namespace P14_1
{
/// <summary>
/// Это главный тип игры
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
//Стартовый экран
SplashScreen splash;
Texture2D splashTexture;
bool firstSplash = true;
//Экран справки
HelpScreen help;
Texture2D helpBack;
Texture2D helpText;
//Экран меню
MenuScreen menu;
Texture2D menuBack;
Texture2D menuGameName;
Texture2D menuTxtStartGame;
Texture2D menuTxtHelp;
Texture2D menuTxtExit;
//Прямоугольники элементов меню
Rectangle m1 = new Rectangle(100, 230, 400, 50);
Rectangle m2 = new Rectangle(100, 320, 400, 50);
Rectangle m3 = new Rectangle(100, 420, 400, 50);
//Игровой экран
GameScreen newGame;
Texture2D gameBall;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.IsFullScreen = true;
// Частота кадра на Windows Phone по умолчанию — 30 кадров в секунду.
TargetElapsedTime = TimeSpan.FromTicks(333333);
// Дополнительный заряд аккумулятора заблокирован.
InactiveSleepTime = TimeSpan.FromSeconds(1);
}
/// <summary>
/// Позволяет игре выполнить инициализацию, необходимую перед запуском.
/// Здесь можно запросить нужные службы и загрузить неграфический
/// контент. Вызов base.Initialize приведет к перебору всех компонентов и
/// их инициализации.
/// </summary>
protected override void Initialize()
{
base.Initialize();
}
/// <summary>
/// LoadContent будет вызываться в игре один раз; здесь загружается
/// весь контент.
/// </summary>
protected override void LoadContent()
{
//Загружаем элементы игры и создаем игровые экраны
spriteBatch = new SpriteBatch(GraphicsDevice);
Services.AddService(typeof(SpriteBatch), spriteBatch);
helpBack = Content.Load<Texture2D>("helpBack");
helpText = Content.Load<Texture2D>("helpText");
help = new HelpScreen(this, helpBack, helpText,
new Rectangle(0, 0, this.Window.ClientBounds.Height, this.Window.ClientBounds.Width),
new Rectangle((this.Window.ClientBounds.Height - helpText.Width) / 2,
(this.Window.ClientBounds.Width - helpText.Height) / 2,
helpText.Width, helpText.Height));
Components.Add(help);
gameBall = Content.Load<Texture2D>("gameObj");
newGame = new GameScreen(this, ref gameBall, new Rectangle(0, 0, 176, 176),
new Vector2(100, 100));
Components.Add(newGame);
menuBack = Content.Load<Texture2D>("menuBack");
menuGameName = Content.Load<Texture2D>("menuGameName");
menuTxtStartGame = Content.Load<Texture2D>("menuTxtStartGame");
menuTxtHelp = Content.Load<Texture2D>("menuTxtHelp");
menuTxtExit = Content.Load<Texture2D>("menuTxtExit");
menu = new MenuScreen(this, menuBack, menuGameName, menuTxtStartGame, menuTxtHelp,
menuTxtExit, m1, m2, m3);
Components.Add(menu);
splashTexture = Content.Load<Texture2D>("splash");
splash = new SplashScreen(this, splashTexture, new Rectangle(0, 0, this.Window.ClientBounds.Height,
this.Window.ClientBounds.Width));
Components.Add(splash);
//Отображаем стартовый экран, остальные элементы скрыты
splash.Show();
}
/// <summary>
/// UnloadContent будет вызываться в игре один раз; здесь выгружается
/// весь контент.
/// </summary>
protected override void UnloadContent()
{
// ЗАДАЧА: выгрузите здесь весь контент, не относящийся к ContentManager
}
//Проверка попадания касания в область, занимаемую меню
private bool MenuSelect(Rectangle m, Vector2 p)
{
bool res = false;
if (p.X > m.X && p.X < m.X + m.Width && p.Y > m.Y && p.Y < m.Y + m.Height)
{
res = true;
}
return res;
}
/// <summary>
/// Позволяет игре запускать логику обновления мира,
/// проверки столкновений, получения ввода и воспроизведения звуков.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Update(GameTime gameTime)
{
//Стартовый экран показываем 2 секунды, после чего показываем
//меню и отключаем показ стартового экрана
if (gameTime.TotalGameTime.Seconds > 2 && firstSplash)
{
splash.Hide();
menu.Show();
firstSplash = false;
}
// Позволяет выйти из игры если кнопка Назад нажата в меню
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed && menu.Enabled)
this.Exit();
//Позволяет перейти к меню, если находимся на экране игры
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed && newGame.Enabled)
{
newGame.Hide();
menu.Show();
}
//Позволяет перейти к меню, если мы находимся на справочном экране
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed && help.Enabled)
{
help.Hide();
menu.Show();
}
//Если активен экран меню, проверяем прикосновения к экрану
if (menu.Enabled)
{
TouchCollection touchLocations = TouchPanel.GetState();
//Если пользователь коснулся экрана и попал в область соответствующего меню
//Поменяем цвет этого пункта меню
foreach (TouchLocation touchLocation in touchLocations)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
if (MenuSelect(m1, touchLocation.Position))
{
menu.Change(1);
}
if (MenuSelect(m2, touchLocation.Position))
{
menu.Change(2);
}
if (MenuSelect(m3, touchLocation.Position))
{
menu.Change(3);
}
}
//Если пользователь убрал палец с экрана, продолжая касаться
//соответствующего пункта меню
if (touchLocation.State == TouchLocationState.Released)
{
if (MenuSelect(m1, touchLocation.Position))
{
menu.Hide();
newGame.Show();
}
if (MenuSelect(m2, touchLocation.Position))
{
menu.Hide();
help.Show();
}
if (MenuSelect(m3, touchLocation.Position))
{
this.Exit();
}
}
}
}
base.Update(gameTime);
}
/// <summary>
/// Вызывается, когда игра отрисовывается.
/// </summary>
/// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
base.Draw(gameTime);
spriteBatch.End();
}
}
}
Листинг
20.7.
Код класса Game1
Особенности работы этого кода раскрыты в комментариях.
20.2. Выводы
В лабораторной работе мы рассмотрели один из методов организации игрового интерфейса, использующего несколько экранов. Помимо представленного метода организации интерфейса пользователя возможны и другие, стандартизированного подхода здесь нет, каждый разработчик создаёт систему игровых экранов сообразно собственным нуждам.
20.3. Задание
Разработайте игровой интерфейс для игры, созданием которой вы занимаетесь.


