Невозможно пройти тесты, в окне с вопросами пусто |
Пользовательский интерфейс в 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. Задание
Разработайте игровой интерфейс для игры, созданием которой вы занимаетесь.