Возможно вы искали: 'Mysteryville'

May 12 2025 01:25:41
  • Как сделать 8Gamers.Ru домашней страницей?
  • Игры
    • База данных по играх
    • Игровые новости
    • Игровая индустрия
    • Обзоры на игры
    • Прохождения игр
    • Гайды к играм
    • Превью о играх
    • Игровые тизеры
    • Игровые арты
    • Игровые обои
    • Игровые скриншоты
    • Игровые обложки
    • Игровые трейлеры
    • Игровое видео
    • Вышедшие игры
    • Ближайшие релизы игр
  • Кино и ТВ
    • База данных по кино
    • Статьи о кино
    • Постеры
    • Кадры из кино
    • Кино трейлеры
    • Сегодня в кино
    • Скоро в кино
  • Комиксы и манга
    • Манга по алфавиту
    • База данных по комиксах
    • Читать онлайн комиксы
    • Читать онлайн манга
    • База персонажей
  • Читы и коды
    • Чит-коды для PC игр
    • Чит-коды для консольных игр
    • Трейнеры
    • Коды Game Genie
  • Моддинг
    • Модификации
    • Карты к играм
    • Программы для моддинга
    • Статьи о моддинге
  • Геймдев
    • Всё о создании игр
    • Список движков
    • Утилиты в помощь игроделу
    • Конструкторы игр
    • Игровые движки
    • Библиотеки разработки
    • 3D-модели
    • Спрайты и тайлы
    • Музыка и звуки
    • Текстуры и фоны
  • Рецензии
    • Игры
    • Кино
    • Аниме
    • Комиксы
    • Мангу
    • Саундтреки
  • Саундтреки
    • Лирика
  • Файлы
    • Патчи к играм
    • Русификаторы к играм
    • Сохранения к играм
    • Субтитры к кино
  • Медиа
    • Видео
    • Фото
    • Аудио
    • Фан-арты
    • Косплей
    • Фото с виставок
    • Девушки из игр
    • Рисунки
    • Рисуем онлайн
    • Фотохостинг
  • Юмор
    • Анекдоты
    • Афоризмы
    • Истории
    • Стишки и эпиграммы
    • Тосты
    • Цитаты
  • Флеш
    • Азартные
    • Аркады
    • Бродилки
    • Гонки
    • Для девочек
    • Для мальчиков
    • Драки
    • Квесты
    • Леталки
    • Логические
    • Мультфильмы
    • Открытки
    • Приколы
    • Разное
    • Спорт
    • Стратегии
    • Стрелялки
Статистика

Статей: 87772
Просмотров: 96030355
Игры
Injustice:  Gods Among Us
Injustice: Gods Among Us
...
Dark Souls 2
Dark Souls 2
Dark Souls II - вторая часть самой хардкорной ролевой игры 2011-2012 года, с новым героем, сюжето...
Battlefield 4
Battlefield 4
Battlefield 4 - продолжение венценосного мультиплеер-ориентированного шутера от первого ли...
Кино
Steins;Gate
Steins;Gate
Любители японской анимации уже давно поняли ,что аниме сериалы могут дать порой гораздо больше пи...
Ку! Кин-дза-дза
Ку! Кин-дза-дза
Начинающий диджей Толик и всемирно известный виолончелист Владимир Чижов встречают на шумной моск...
Обзоры на игры
• Обзор Ibara [PCB/PS2] 18346
• Обзор The Walking ... 18789
• Обзор DMC: Devil M... 19864
• Обзор на игру Valk... 15867
• Обзор на игру Stars! 17754
• Обзор на Far Cry 3 17935
• Обзор на Resident ... 16012
• Обзор на Chivalry:... 17495
• Обзор на игру Kerb... 17970
• Обзор игры 007: Fr... 16604
Превью о играх
• Превью к игре Comp... 17946
• Превью о игре Mage... 14451
• Превью Incredible ... 14706
• Превью Firefall 13462
• Превью Dead Space 3 16325
• Превью о игре SimC... 14717
• Превью к игре Fuse 15432
• Превью Red Orche... 15532
• Превью Gothic 3 16334
• Превью Black & W... 17345
Главная » Статьи » Всё о XNA » Простой менеджер игровых экранов (ScreenManager)

Простой менеджер игровых экранов (ScreenManager)

Простой менеджер игровых экранов (ScreenManager)

Данная статья предназначена для ознакомления и использования в личных целях, не претендует на уникальность и единственное решение поставленной задачи.
Статья рекомендована к ознакомлению новичкам, начинающим и продолжающим программирование игр на C# & XNA4.

Не секрет, что, начав осваивать новую платформу/среду/инструмент (не обязательно это XNA), поигравшись с ним, откомпилировав первый Hello, World!, многие начинают расширять свои навыки владения инструментом.
Для разработчиков на XNA первым и необходимым источником является AppHub.
Так как данная статья описывает реализацию Game Screens, или Игровых Экранов, то, найдя в упомянутом AppHub пример GameStateManagement многие новички впадают в ужас при виде всего того, что там "навалено".
Собственно, статья как раз и рассматривает создание более простого подхода к организации Игровых Экранов. И не только экранов. Поехали.

Запускаем студию, создаем проект. Название оставляем по умолчанию, WindowsGame1:



Основой всего происходящего в примере будет статический класс (да-да, даже не компонент), назовем его ScreenManager.
Для этого добавляем к пока пустому проекту папку ScreenManager:



и добавляем в эту папку класс ScreenManager.cs (прим.: расширение .cs в названии класса можно не указывать, само добавится):



Исходный код класса (здесь и далее исходник приведен полный, в комментариях думаю не нуждается):



Код
using System.Collections.Generic;
using Microsoft.Xna.Framework;

namespace WindowsGame1
{
internal static class ScreenManager
{
static List screens = new List();
static bool isStarted = false;
static Screen prevScreen = null;
internal static Screen ActiveScreen = null;

internal static void AddScreen(Screen screen)
{
foreach (Screen scr in screens)
if (scr.Name == screen.Name)
return;

screens.Add(screen);
}

internal static int GetScreensCount()
{
return screens.Count;
}

internal static Screen GetScreenByIndex(int index)
{
return screens[index];
}

internal static Screen GetScreenByName(string name)
{
foreach (Screen scr in screens)
if (scr.Name == name)
return scr;

return null;
}

internal static void ActivateScreen(Screen screen)
{
prevScreen = ActiveScreen;

if (ActiveScreen != null)
ActiveScreen.Remove();

ActiveScreen = screen;

if (isStarted)
ActiveScreen.Initialize();
}

internal static void ActivateScreenByIndex(int index)
{
prevScreen = ActiveScreen;

if (ActiveScreen != null)
ActiveScreen.Remove();

ActiveScreen = GetScreenByIndex(index);

if (isStarted)
ActiveScreen.Initialize();
}

internal static void ActivateScreenByName(string name)
{
prevScreen = ActiveScreen;

ActiveScreen = GetScreenByName(name);

if (isStarted)
ActiveScreen.Initialize();
}

internal static void ActivatePreviousScreen()
{
if (prevScreen != null)
ActivateScreenByName(prevScreen.Name);
}

internal static void Initialize()
{
isStarted = true;

if (ActiveScreen != null)
ActiveScreen.Initialize();
}

internal static void Update(GameTime gameTime)
{
if (!isStarted)
return;

if (ActiveScreen != null)
ActiveScreen.Update(gameTime);
}

internal static void Draw(GameTime gameTime)
{
if (!isStarted)
return;

if (ActiveScreen != null)
ActiveScreen.Draw(gameTime);
}

}
}




Наш менеджер игровых экранов оперирует неким объектом Screen, о котором пока не знает студия:



Так что же это за объект?
Это наш будущий базовый класс для всех игровых экранов. Он содержит минимум необходимых виртуальных методов, необходимых для отрисовки и обновления экрана-наследника, которые будем переопределять в наследуемых от него экранах.
Для начала создадим еще один класс Screen.cs в папке ScreenManager. Вот его полный исходный код:

Код
using Microsoft.Xna.Framework;

namespace WindowsGame1
{
internal class Screen
{
internal string Name { get; private set; }

internal Screen(string name)
{
Name = name;
}

internal virtual bool Initialize() { return true; }

internal virtual void Remove() { }

internal virtual void Update(GameTime gameTime) { }

internal virtual void Draw(GameTime gameTime) { }

}
}




Итак, наш менеджер экранов уже готов к работе, и настало время попробовать его использовать.
Но для начала создадим еще один статический класс-"хранилище" ссылок на общеигровые объекты нашей игры. Этот класс обеспечит нам доступ к необходимым объектам, так как ScreenManager является не GameComponent. Вот его исходный код:

Код
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace WindowsGame1
{
internal static class Commons
{
internal static Game Game;
internal static ContentManager Content;
internal static GraphicsDevice GraphicsDevice;
internal static SpriteBatch SpriteBatch;
}
}




Определим поля класса Commons и проинициализируем наш менеджер в "главном" классе Game1:

Код
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace WindowsGame1
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;

public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";

IsMouseVisible = true;
}

protected override void Initialize()
{
base.Initialize();
}

protected override void LoadContent()
{
Commons.Game = this;
Commons.Content = Content;
Commons.GraphicsDevice = graphics.GraphicsDevice;
Commons.SpriteBatch = new SpriteBatch(graphics.GraphicsDevice);

ScreenManager.AddScreen(new MainMenuScreen());
ScreenManager.AddScreen(new TestScreen());
ScreenManager.ActivateScreenByName("MainMenuScreen");
ScreenManager.Initialize();
}

protected override void UnloadContent()
{
}

protected override void Update(GameTime gameTime)
{
ScreenManager.Update(gameTime);
InputManager.Update(gameTime);

base.Update(gameTime);
}

protected override void Draw(GameTime gameTime)
{
ScreenManager.Draw(gameTime);

base.Draw(gameTime);
}

}
}




Как видно, мы убрали из Game1 экземпляр класса SpriteBatch, и "перенесли" его в Commons.
Также убрана очистка буфера экрана GraphicsDevice.Clear(Color.CornflowerBlue); в методе Draw(), так как отрисовка будет выполняться в наших игровых экранах.

Теперь добавим в нашу игру пару экранов: MainMenuScreen и TestScreen в новую папку Screens проекта. Для наглядной реализации в проекте сделаны лишь переходы между экранами. Этого вполне достаточно чтобы убедиться в работоспособности менеджера.
Забегая немного вперед отмечу, что в классах экранов мы опять увидим некий объект MenuItem. Это простой класс элемента меню, со своими полями и свойствами, облегчающими обработку состояния каждого элемента меню. Организация меню в целом и пунктов меню не совсем идеальная, но суть понятна из простой реализации. Вот его код:

Код
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace WindowsGame1
{
internal class MenuItem
{
internal string Text { get; private set; }
internal SpriteFont Font { get; private set; }
internal Vector2 Position { get; private set; }
internal Rectangle Rect { get; private set; }
internal Action Action { get; private set; }

internal MenuItem(string text, SpriteFont font, Vector2 position, Action action)
{
Text = text;
Font = font;
Vector2 measure = font.MeasureString(Text);

Position = new Vector2(
(int)(position.X - measure.X / 2),
(int)(position.Y - measure.Y / 2));

Rect = new Rectangle(
(int)Position.X,
(int)Position.Y,
(int)measure.X,
(int)measure.Y);

Action = action;
}
internal bool Hovered()
{
return Rect.Contains(InputManager.GetMousePositionToPoint());
}

internal bool Clicked()
{
return Hovered() && InputManager.IsMouseLeftClick();
}

}
}




Здесь нам встретилось еще одно "существо" InputManager. Это такой же статический класс, выдающий нам по запросу состояния игровых контроллеров. В рамках статьи в нем реализовано лишь обновление клавиатуры и мыши:

Код
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace WindowsGame1
{
internal static class InputManager
{
static KeyboardState keyState;
static KeyboardState keyOldState;
static MouseState mouseState;
static MouseState mouseOldState;

static InputManager()
{
}

internal static void Update(GameTime gameTime)
{
keyOldState = keyState;
mouseOldState = mouseState;

keyState = Keyboard.GetState();
mouseState = Mouse.GetState();
}

internal static bool IsKeyDown(Keys key)
{
return keyState.IsKeyDown(key);
}

internal static bool IsKeyPress(Keys key)
{
return IsKeyDown(key) && keyOldState.IsKeyUp(key);
}

internal static bool IsMouseLeftDown()
{
return mouseState.LeftButton == ButtonState.Pressed;
}

internal static bool IsMouseLeftClick()
{
return IsMouseLeftDown() && mouseOldState.LeftButton == ButtonState.Released;
}

internal static bool IsMouseRightDown()
{
return mouseState.RightButton == ButtonState.Pressed;
}

internal static bool IsMouseRightClick()
{
return IsMouseRightDown() && mouseOldState.RightButton == ButtonState.Released;
}

internal static bool IsMouseMiddleDown()
{
return mouseState.MiddleButton == ButtonState.Pressed;
}

internal static bool IsMouseMiddleClick()
{
return IsMouseMiddleDown() && mouseOldState.MiddleButton == ButtonState.Released;
}

internal static bool IsMouseWheelUp()
{
return mouseState.ScrollWheelValue > mouseOldState.ScrollWheelValue;
}

internal static bool IsMouseWheelDown()
{
return mouseState.ScrollWheelValue < mouseOldState.ScrollWheelValue;
}

internal static Vector2 GetMousePositionToVector2()
{
return new Vector2(mouseState.X, mouseState.Y);
}

internal static Point GetMousePositionToPoint()
{
return new Point(mouseState.X, mouseState.Y);
}

}
}




Экран MainMenuScreen содержит лишь два пункта меню: "Играть" и "Выход":



Код
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;

namespace WindowsGame1
{
internal class MainMenuScreen : Screen
{
SpriteFont font;
List menuItems = new List();
Color itemNormalColor = Color.White;
Color itemHoverColor = Color.Red;

internal MainMenuScreen()
: base("MainMenuScreen")
{
}

internal override bool Initialize()
{
font = Commons.Content.Load("Fonts/menuFont");

menuItems.AddRange(new MenuItem[]
{
new MenuItem(
"Play / Играть",
font,
new Vector2(
Commons.GraphicsDevice.Viewport.Width / 2,
Commons.GraphicsDevice.Viewport.Height * 4 / 6),
new Action(() => { ScreenManager.ActivateScreenByName("TestScreen"); } )),
new MenuItem(
"Exit / Выход",
font,
new Vector2(
Commons.GraphicsDevice.Viewport.Width / 2,
Commons.GraphicsDevice.Viewport.Height * 5 / 6),
new Action(() => { Commons.Game.Exit(); } )),
});

return base.Initialize();
}

internal override void Remove()
{
base.Remove();
}

internal override void Update(GameTime gameTime)
{
if (InputManager.IsKeyPress(Keys.Escape))
Commons.Game.Exit();

for (int i = 0; i < menuItems.Count; i++)
{
if (menuItems.Clicked())
{
menuItems.Action.Invoke();
break;
}
}

base.Update(gameTime);
}

internal override void Draw(GameTime gameTime)
{
Commons.GraphicsDevice.Clear(Color.Gray);

Commons.SpriteBatch.Begin();

for (int i = 0; i < menuItems.Count; i++)
{
Commons.SpriteBatch.DrawString(
font,
menuItems.Text,
menuItems.Position,
menuItems.Hovered() ? itemHoverColor : itemNormalColor);
}

Commons.SpriteBatch.End();

base.Draw(gameTime);
}

}
}




Пункт "Играть" указывает нашему ScreenManager, чтобы тот "переключил" игровой экран на TestScreen. Клавишей Escape игра завершается.
Экран TestScreen содержит экземпляр MenuItem, у которого Action "просит" ScreenManager переключить экран на MainMenuScreen. То же самое происходит по нажатию клавиши Escape.
Также в центре этого экрана для наглядности крутится сфера с текстурой нашей планеты. Модель очень низкополигональная, ибо это не суть совсем, главное механизм в целом. Для интересующихся количеством полигонов скрин с блендера ниже по тексту.



Код
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;

namespace WindowsGame1
{
internal class TestScreen : Screen
{
SpriteFont font;
List menuItems = new List();
Color itemNormalColor = Color.White;
Color itemHoverColor = Color.Red;

Model sphere;
Matrix world;
Matrix view;
Matrix proj;

internal TestScreen()
: base("TestScreen")
{
world = Matrix.Identity;
view = Matrix.CreateLookAt(
new Vector3(5f, 1f, 0f),
Vector3.Zero,
Vector3.Up);
proj = Matrix.CreatePerspectiveFieldOfView(
MathHelper.PiOver4,
Commons.GraphicsDevice.Viewport.AspectRatio,
0.1f, 10f);
}

internal override bool Initialize()
{
font = Commons.Content.Load("Fonts/font1");
sphere = Commons.Content.Load("Models/sphere");

menuItems.AddRange(new MenuItem[]
{
new MenuItem(
"Меню",
font,
new Vector2(
Commons.GraphicsDevice.Viewport.Width - font.MeasureString("Меню").X,
font.MeasureString("Меню").Y / 2),
new Action(() => { ScreenManager.ActivateScreenByName("MainMenuScreen"); } )),
});

return base.Initialize();
}

internal override void Remove()
{
base.Remove();
}

internal override void Update(GameTime gameTime)
{
if (InputManager.IsKeyPress(Keys.Escape))
ScreenManager.ActivateScreenByName("MainMenuScreen");

for (int i = 0; i < menuItems.Count; i++)
{
if (menuItems.Clicked())
{
menuItems.Action.Invoke();
break;
}
}

world *= Matrix.CreateRotationY((float)gameTime.ElapsedGameTime.TotalSeconds);

base.Update(gameTime);
}

internal override void Draw(GameTime gameTime)
{
Commons.GraphicsDevice.Clear(Color.Transparent);

Commons.SpriteBatch.Begin();

for (int i = 0; i < menuItems.Count; i++)
{
Commons.SpriteBatch.DrawString(
font,
menuItems.Text,
menuItems.Position,
menuItems.Hovered() ? itemHoverColor : itemNormalColor);
}

Commons.SpriteBatch.End();

sphere.Draw(world, view, proj);

base.Draw(gameTime);
}

}
}




Модель сферы в исходном виде в окне блендера:



Как видно, ничего сложного в реализации классов экранов нет, всё это Вы уже проделывали, упражняясь с программированием в XNA GS, только код был прямо в Game1. В подходе, описанном в статье, сохраняется эта простота, как если бы Вы писали код только для одного, главного экрана.
1378 Прочтений •  [Простой менеджер игровых экранов (ScreenManager)] [26.03.2012] [****] [Комментариев: 0]
Добавил: Ukraine Vova
Ссылки
HTML: 
[BB Url]: 
Похожие статьи
Название Добавил Добавлено
• Простой менеджер игровых экранов (S... Ukraine Vova 26.03.2012
Ни одного комментария? Будешь первым :).
Пожалуйста, авторизуйтесь для добавления комментария.

Проект входит в сеть сайтов «8Gamers Network»

Все права сохранены. 8Gamers.NET © 2011 - 2025

Статьи
Рецензия на Pressure
Рецензия на Pressure
Чтобы обратить на себя внимание, начинающие маленькие разработчики, как правило, уходят в жанры, ...
Рецензия на Lost Chronicles of Zerzura
Рецензия на Lost Chron...
Игры, сделанные без любви и старания, похожи на воздушный шар – оболочка есть, а внутри пусто. Lo...
Рецензия на The Bridge
Рецензия на The Bridge
«Верх» и «низ» в The Bridge — понятия относительные. Прогуливаясь под аркой, можно запросто перей...
Рецензия на SimCity
Рецензия на SimCity
Когда месяц назад состоялся релиз SimCity, по Сети прокатилось цунами народного гнева – глупые ош...
Рецензия на Strategy & Tactics: World War 2
Рецензия на Strategy &...
Название Strategy & Tactics: World War II вряд ли кому-то знакомо. Зато одного взгляда на ее скри...
Рецензия на игру Scribblenauts Unlimited
Рецензия на игру Scrib...
По сложившейся традиции в информационной карточке игры мы приводим в пример несколько похожих игр...
Рецензия на игру Walking Dead: Survival Instinct, The
Рецензия на игру Walki...
Зомби и продукция-по-лицензии — которые и сами по себе не лучшие представители игровой биосферы —...
Обратная связь | RSS | Донейт | Статистика | Команда | Техническая поддержка