Цель работы: Научиться разрабатывать пользовательский интерфейс для XNA-игр
Пользовательский интерфейс для XNA-программ нужно разрабатывать самостоятельно, создавая собственные элементы управления. Если интерфейс игры не слишком сложен, его можно реализовать полностью на XNA, если же есть необходимость в использовании сложных элементов управления (наподобие выпадающих списков), есть смысл задуматься о применении
Мы разработаем систему интерфейса, состоящую из нескольких экранов.
При запуске игры на несколько секунд будет появляться стартовый экран. Обычно его называют splash-
В нашем случае мы отображаем его определенное время, после чего будет выводиться экран, отображающий меню игры. С этого экрана можно попасть на экран игровой справки, запустить основную
Ранее нажатие на эту кнопку завершало программу. Теперь мы построили на её основе систему перехода по экранам программы, выглядящую следующим образом. Если отображается экран меню, нажатие на эту кнопку приводит к выходу из программы. Если отображается основной экран игры либо экран справки, нажатие на эту кнопку приводит к переходу к экрану меню.
Такое поведение кнопки Назад характерно для приложений на Windows Phone, её нажатие на экране, не являющимся главным, не должно приводить к завершению работы приложения. Если это оправдано структурой интерфейса, вы вполне можете дополнить данную возможность экранными элементами управления. Например, в сложном многоуровневом меню это вполне логично. Но – лишь дополнить, помня о необходимости правильной обработки нажатия на кнопку Назад.
Создадим новый игровой проект P14_1. На рис. 20.1 вы можете видеть его окно Обозреватель Решений.
(рис 20.1) Обозреватель решений
Проект включает в себя множество классов, основным является класс . Он (листинг 20.1.) реализует процедуры управления экранами с помощью методов Show() и , которые используются для управления свойствами игрового компонента (DrawableGameComponent)
Если установлено в значение Истина, для этого компонента вызывается метод Draw, отвечающий за отрисовку данных, сгенерированных объектом. В противном случае этот метод не вызывается.
Свойство Enabled отвечает за вызов Update. Таким образом, если оба свойства установлены в значение
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace P14_1
{
/// <summary>
/// Это игровой компонент, реализующий интерфейс IUpdateable.
/// </summary>
//Базовый класс, на основе которого создаются игровые экраны
public class Screen : Microsoft.Xna.Framework.DrawableGameComponent
{
//Для объекта SpriteBatch, который используется
//для вывода изображений в классах-наследниках
public SpriteBatch sprBatch;
public Screen(Game game)
: base(game)
{
//При создании объекта он по умолчанию
//невидим и неактивен
Visible = false;
Enabled = false;
//получим объект SpriteBatch
sprBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
}
//Процедура для отображения и активации объекта
public void Show()
{
Visible = true;
Enabled = true;
}
//Процедура для скрытия и отключения объекта
public void Hide()
{
Visible = false;
Enabled = false;
}
}
}
Ниже приведен код класса стартового экрана, листинг 20.2.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace P14_1
{
class SplashScreen: Screen
{
//Текстуры для фона и справочной надписи
Texture2D backTexture;
Rectangle backRectangle;
public SplashScreen(Game game, Texture2D _back, Rectangle _backRec)
: base(game)
{
backTexture = _back;
backRectangle = _backRec;
}
public override void Draw(GameTime gameTime)
{
//Выводим изображения
sprBatch.Draw(backTexture, backRectangle, Color.White);
base.Draw(gameTime);
}
}
}
Здесь мы, в конструкторе, принимаем данные для вывода изображения и выводим его в методе Draw. Стартовый экран вы можете видеть на рис. 20.2
(рис 20.2) Стартовый экран игры
В листинге 20.3 приведен код класса MenuScreen.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace P14_1
{
class MenuScreen: Screen
{
//Элементы меню будем хранить в массиве типа Menu
//тип данных Menu хранит информацию об элементах меню
Menu[] menu;
//Текстуры и прямоугольники для вывода элементов меню
Texture2D menuTxtStartGame;
Texture2D menuTxtHelp;
Texture2D menuTxtExit;
Rectangle menuTxtStartGameR, menuTxtHelpR, menuTxtExitR;
Texture2D menuBack, menuGameName;
Rectangle menuBackR, menuGameNameR;
public MenuScreen(Game game, Texture2D _menuBack, Texture2D _menuGameName,
Texture2D _menuTxtStartGame, Texture2D _menuTxtHelp, Texture2D _menuTxtExit,
Rectangle _menuTxtStartGameR, Rectangle _menuTxtHelpR, Rectangle _menuTxtExitR)
: base(game)
{
menuBack = _menuBack;
menuGameName = _menuGameName;
menuBackR = new Rectangle(0, 0, 800, 480);
menuGameNameR = new Rectangle(0, 0, 800, 200);
menuTxtStartGame = _menuTxtStartGame;
menuTxtStartGameR = _menuTxtStartGameR;
menuTxtHelp = _menuTxtHelp;
menuTxtHelpR = _menuTxtHelpR;
menuTxtExit = _menuTxtExit;
menuTxtExitR = _menuTxtExitR;
//Создаем массив из 3-х элементов
menu = new P14_1.Menu[3];
//Инициализируем элементы массива
//Элемент с номером 0 активен
menu[0] = new P14_1.Menu(game, menuTxtStartGame, menuTxtStartGameR, Color.Magenta);
menu[1] = new P14_1.Menu(game, menuTxtHelp, menuTxtHelpR, Color.White);
menu[2] = new P14_1.Menu(game, menuTxtExit, menuTxtExitR, Color.White);
}
//Метод вызывается для отображения смены пункта меню
public void Change(int i)
{
//i=1 - первый пункт
//i=2 - второй пункт
//i=3 - третий пункт
if (i == 1)
{
menu[0].color = Color.Magenta;
menu[1].color = Color.White;
menu[2].color = Color.White;
}
if (i == 2)
{
menu[0].color = Color.White;
menu[1].color = Color.Magenta;
menu[2].color = Color.White;
}
if (i == 3)
{
menu[0].color = Color.White;
menu[1].color = Color.White;
menu[2].color = Color.Magenta;
}
}
//Рисование элементов
public override void Draw(GameTime gameTime)
{
//Вывод фона и названия игры
sprBatch.Draw(menuBack, menuBackR, Color.White);
sprBatch.Draw(menuGameName, menuGameNameR, Color.White);
//Вывод элементов меню
for (int i = 0; i < 3; i++)
sprBatch.Draw(menu[i].imageTexture, menu[i].imageRectangle, menu[i].color);
base.Draw(gameTime);
}
}
}
Здесь мы выводим элементы меню, данные по которым хранятся в массиве, что позволяет удобно расширять меню. Кроме того, класс имеет метод Change, который позволяет активировать пункт меню, которого коснулся пользователь, меняя его цвет.
Этот класс использует класс
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.3.
(рис 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.4.
(рис 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.5.
(рис 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();
}
}
}
Особенности работы этого кода раскрыты в комментариях.
В лабораторной работе мы рассмотрели один из методов организации игрового интерфейса, использующего несколько экранов. Помимо представленного метода организации интерфейса пользователя возможны и другие, стандартизированного подхода здесь нет, каждый разработчик создаёт систему игровых экранов сообразно собственным нуждам.
Разработайте игровой интерфейс для игры, созданием которой вы занимаетесь.
К данной лабораторной работе прилагается видеоурок
и демонстрационный проект.
Цель работы: Научиться разрабатывать пользовательский интерфейс для XNA-игр
Пользовательский интерфейс для XNA-программ нужно разрабатывать самостоятельно, создавая собственные элементы управления. Если интерфейс игры не слишком сложен, его можно реализовать полностью на XNA, если же есть необходимость в использовании сложных элементов управления (наподобие выпадающих списков), есть смысл задуматься о применении
Мы разработаем систему интерфейса, состоящую из нескольких экранов.
При запуске игры на несколько секунд будет появляться стартовый экран. Обычно его называют splash-
В нашем случае мы отображаем его определенное время, после чего будет выводиться экран, отображающий меню игры. С этого экрана можно попасть на экран игровой справки, запустить основную
Ранее нажатие на эту кнопку завершало программу. Теперь мы построили на её основе систему перехода по экранам программы, выглядящую следующим образом. Если отображается экран меню, нажатие на эту кнопку приводит к выходу из программы. Если отображается основной экран игры либо экран справки, нажатие на эту кнопку приводит к переходу к экрану меню.
Такое поведение кнопки Назад характерно для приложений на Windows Phone, её нажатие на экране, не являющимся главным, не должно приводить к завершению работы приложения. Если это оправдано структурой интерфейса, вы вполне можете дополнить данную возможность экранными элементами управления. Например, в сложном многоуровневом меню это вполне логично. Но – лишь дополнить, помня о необходимости правильной обработки нажатия на кнопку Назад.
Создадим новый игровой проект P14_1. На рис. 20.1 вы можете видеть его окно Обозреватель Решений.
(рис 20.1) Обозреватель решений
Проект включает в себя множество классов, основным является класс . Он (листинг 20.1.) реализует процедуры управления экранами с помощью методов Show() и , которые используются для управления свойствами игрового компонента (DrawableGameComponent)
Если установлено в значение Истина, для этого компонента вызывается метод Draw, отвечающий за отрисовку данных, сгенерированных объектом. В противном случае этот метод не вызывается.
Свойство Enabled отвечает за вызов Update. Таким образом, если оба свойства установлены в значение
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace P14_1
{
/// <summary>
/// Это игровой компонент, реализующий интерфейс IUpdateable.
/// </summary>
//Базовый класс, на основе которого создаются игровые экраны
public class Screen : Microsoft.Xna.Framework.DrawableGameComponent
{
//Для объекта SpriteBatch, который используется
//для вывода изображений в классах-наследниках
public SpriteBatch sprBatch;
public Screen(Game game)
: base(game)
{
//При создании объекта он по умолчанию
//невидим и неактивен
Visible = false;
Enabled = false;
//получим объект SpriteBatch
sprBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
}
//Процедура для отображения и активации объекта
public void Show()
{
Visible = true;
Enabled = true;
}
//Процедура для скрытия и отключения объекта
public void Hide()
{
Visible = false;
Enabled = false;
}
}
}
Ниже приведен код класса стартового экрана, листинг 20.2.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace P14_1
{
class SplashScreen: Screen
{
//Текстуры для фона и справочной надписи
Texture2D backTexture;
Rectangle backRectangle;
public SplashScreen(Game game, Texture2D _back, Rectangle _backRec)
: base(game)
{
backTexture = _back;
backRectangle = _backRec;
}
public override void Draw(GameTime gameTime)
{
//Выводим изображения
sprBatch.Draw(backTexture, backRectangle, Color.White);
base.Draw(gameTime);
}
}
}
Здесь мы, в конструкторе, принимаем данные для вывода изображения и выводим его в методе Draw. Стартовый экран вы можете видеть на рис. 20.2
(рис 20.2) Стартовый экран игры
В листинге 20.3 приведен код класса MenuScreen.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace P14_1
{
class MenuScreen: Screen
{
//Элементы меню будем хранить в массиве типа Menu
//тип данных Menu хранит информацию об элементах меню
Menu[] menu;
//Текстуры и прямоугольники для вывода элементов меню
Texture2D menuTxtStartGame;
Texture2D menuTxtHelp;
Texture2D menuTxtExit;
Rectangle menuTxtStartGameR, menuTxtHelpR, menuTxtExitR;
Texture2D menuBack, menuGameName;
Rectangle menuBackR, menuGameNameR;
public MenuScreen(Game game, Texture2D _menuBack, Texture2D _menuGameName,
Texture2D _menuTxtStartGame, Texture2D _menuTxtHelp, Texture2D _menuTxtExit,
Rectangle _menuTxtStartGameR, Rectangle _menuTxtHelpR, Rectangle _menuTxtExitR)
: base(game)
{
menuBack = _menuBack;
menuGameName = _menuGameName;
menuBackR = new Rectangle(0, 0, 800, 480);
menuGameNameR = new Rectangle(0, 0, 800, 200);
menuTxtStartGame = _menuTxtStartGame;
menuTxtStartGameR = _menuTxtStartGameR;
menuTxtHelp = _menuTxtHelp;
menuTxtHelpR = _menuTxtHelpR;
menuTxtExit = _menuTxtExit;
menuTxtExitR = _menuTxtExitR;
//Создаем массив из 3-х элементов
menu = new P14_1.Menu[3];
//Инициализируем элементы массива
//Элемент с номером 0 активен
menu[0] = new P14_1.Menu(game, menuTxtStartGame, menuTxtStartGameR, Color.Magenta);
menu[1] = new P14_1.Menu(game, menuTxtHelp, menuTxtHelpR, Color.White);
menu[2] = new P14_1.Menu(game, menuTxtExit, menuTxtExitR, Color.White);
}
//Метод вызывается для отображения смены пункта меню
public void Change(int i)
{
//i=1 - первый пункт
//i=2 - второй пункт
//i=3 - третий пункт
if (i == 1)
{
menu[0].color = Color.Magenta;
menu[1].color = Color.White;
menu[2].color = Color.White;
}
if (i == 2)
{
menu[0].color = Color.White;
menu[1].color = Color.Magenta;
menu[2].color = Color.White;
}
if (i == 3)
{
menu[0].color = Color.White;
menu[1].color = Color.White;
menu[2].color = Color.Magenta;
}
}
//Рисование элементов
public override void Draw(GameTime gameTime)
{
//Вывод фона и названия игры
sprBatch.Draw(menuBack, menuBackR, Color.White);
sprBatch.Draw(menuGameName, menuGameNameR, Color.White);
//Вывод элементов меню
for (int i = 0; i < 3; i++)
sprBatch.Draw(menu[i].imageTexture, menu[i].imageRectangle, menu[i].color);
base.Draw(gameTime);
}
}
}
Здесь мы выводим элементы меню, данные по которым хранятся в массиве, что позволяет удобно расширять меню. Кроме того, класс имеет метод Change, который позволяет активировать пункт меню, которого коснулся пользователь, меняя его цвет.
Этот класс использует класс
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.3.
(рис 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.4.
(рис 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.5.
(рис 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();
}
}
}
Особенности работы этого кода раскрыты в комментариях.
В лабораторной работе мы рассмотрели один из методов организации игрового интерфейса, использующего несколько экранов. Помимо представленного метода организации интерфейса пользователя возможны и другие, стандартизированного подхода здесь нет, каждый разработчик создаёт систему игровых экранов сообразно собственным нуждам.
Разработайте игровой интерфейс для игры, созданием которой вы занимаетесь.
К данной лабораторной работе прилагается видеоурок
и демонстрационный проект.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.