Использование системы интерфейса MyGUI
Продолжаем работу над нашим проектом. В данной статье я опишу как подключить к проекту систему пользовательского интерфейса MyGUI. Вообще в Ogre3D уже есть встроенная система интерфейса, но она не очень удобна в работе, поэтому сторонними разработчиками были написаны несколько альтернативных систем. Лично я экспериментировал с двумя из них MyGUI и QuickGUI. MyGUI написана нашими соотечественниками и у неё очень красивые примеры, поэтому я решил остановиться на ней :).
Сначала необходимо скачать и откомпилировать собственно библиотеку MyGUI. Скачать ее можно с сайта http://my-gui.sourceforge.net.
Компиляция библиотеки аналогична компиляции нашего проекта, поэтому сложностей с этим возникнуть не должно.
После сборки библиотеки, попробуем использовать её в игре. Для этого добавим два новых файла в проект Game.h и Game.cpp, в этих файлах описывается класс Game, который будет отвечать за весь игровой процесс в целом.
Ниже приводиться полное содержание файла Game.h
#ifndef __GAME_H__
#define __GAME_H__
#include <MyGUI.h>
#include <OIS/OISEvents.h>
class Application;
enum GameState {
GAME_STATE_NONE = 0,
GAME_STATE_MAIN_MENU,
GAME_STATE_SETTINGS_MENU,
GAME_STATE_PLAY_GAME
};
#define GAME_UPDATE_FPS 20.0f
//---------------------------------------------------------
// Игра
//---------------------------------------------------------
class Game
{
Application* _app;
int _state;
Ogre::Camera* _camera;
public:
Game();
~Game();
Ogre::Camera* GetCamera() { return _camera; }
// Игровой процесс
void Update(float time);
// Игровые состояния
void StartMainMenu();
// Делегаты
void MainMenuDelegate(MyGUI::WidgetPtr widget);
// Обработка событий
bool EventKeyPressed(const OIS::KeyEvent &keyEventRef);
bool EventKeyReleased(const OIS::KeyEvent &keyEventRef);
bool EventMouseMoved(const OIS::MouseEvent &evt);
bool EventMousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id);
bool EventMouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id);
};
#endif
Разберем этот код поближе. Прежде всего здесь описываются игровые состояния:
enum GameState {
GAME_STATE_NONE = 0,
GAME_STATE_MAIN_MENU,
GAME_STATE_SETTINGS_MENU,
GAME_STATE_PLAY_GAME
};
Игровые состояния нужны для того, чтобы например различать когда мы находимся в начальном меню, а когда в игре и т.п. И соответственно по разному обрабатывать ввод от пользователя.
Дальше мы видим описания функций, которые будут обрабатывать возникающие события:
// Делегаты void MainMenuDelegate(MyGUI::WidgetPtr widget); // Обработка событий bool EventKeyPressed(const OIS::KeyEvent &keyEventRef); bool EventKeyReleased(const OIS::KeyEvent &keyEventRef); bool EventMouseMoved(const OIS::MouseEvent &evt); bool EventMousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id); bool EventMouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id);
Здесь, уже знакомые нам функции обработки ввода с клавиатуры и мышки. А также функция-делегат для обработки всех событий интерфейса, возникающих в начальном меню. Делегатом в MyGUI называется функция, в которой производится обработка событий, происходящих в интерфейсе. В примерах использования библиотеки каждой кнопке назначается свой делегат, но чтобы не плодить функции, я направляю все события в один обработчик.
А теперь рассмотрим сам код. Ниже приведен текст файла Game.cpp
#include "Game.h"
#include "Application.h"
//---------------------------------------------------------
// Конструктор
//---------------------------------------------------------
Game::Game()
{
_state = GAME_STATE_NONE;
_app = &Application::getInstance();
_camera = Ogre::Root::getSingletonPtr()->getSceneManager("SceneManager")->createCamera("Camera");
_camera->setPosition(-400, 300, -400);
_camera->lookAt(0,0,0);
_camera->setNearClipDistance(1);
}
//---------------------------------------------------------
// Деструктор
//---------------------------------------------------------
Game::~Game()
{
}
//---------------------------------------------------------
// Переход в основное меню
//---------------------------------------------------------
void Game::StartMainMenu()
{
_app->GetGui()->load("main_menu.layout");
MyGUI::IntSize view = _app->GetGui()->getViewSize();
MyGUI::WidgetPtr window = _app->GetGui()->findWidget<MyGUI::Widget>("MainMenu");
window->setPosition(view.width/2 - window->getWidth()/2, view.height/2 - window->getHeight()/2);
MyGUI::ControllerFadeAlpha * controller = new MyGUI::ControllerFadeAlpha(window->getAlpha(), 2, true);
window->setAlpha(0);
MyGUI::ControllerManager::getInstance().addItem(window, controller);
MyGUI::ButtonPtr button = _app->GetGui()->findWidget<MyGUI::Button>("ExitButton");
button->eventMouseButtonClick = MyGUI::newDelegate(this, &Game::MainMenuDelegate);
button = _app->GetGui()->findWidget<MyGUI::Button>("StartButton");
button->eventMouseButtonClick = MyGUI::newDelegate(this, &Game::MainMenuDelegate);
button = _app->GetGui()->findWidget<MyGUI::Button>("SettingsButton");
button->eventMouseButtonClick = MyGUI::newDelegate(this, &Game::MainMenuDelegate);
_state = GAME_STATE_MAIN_MENU;
}
//---------------------------------------------------------
// Обработка сообщений начального меню
//---------------------------------------------------------
void Game::MainMenuDelegate(MyGUI::WidgetPtr widget)
{
if(widget->getName() == "ExitButton") {
_app->Shutdown();
}
}
//---------------------------------------------------------
// Обработка нажатия клавиши
//---------------------------------------------------------
bool Game::EventKeyPressed(const OIS::KeyEvent &evt)
{
return true;
}
//---------------------------------------------------------
// Обработка отпускания клавиши
//---------------------------------------------------------
bool Game::EventKeyReleased(const OIS::KeyEvent &evt)
{
return true;
}
//---------------------------------------------------------
// Обработка движения мышки
//---------------------------------------------------------
bool Game::EventMouseMoved(const OIS::MouseEvent &evt)
{
return true;
}
//---------------------------------------------------------
// Обработка нажатий клавиш мышки
//---------------------------------------------------------
bool Game::EventMousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
return true;
}
//---------------------------------------------------------
// Обработка отпусканий клавиш мышки
//---------------------------------------------------------
bool Game::EventMouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
return true;
}
В этом файле нас интересует функция StartMainMenu, в которой происходит настройка главного меню.
Разберем её содержимое:
_app->GetGui()->load("main_menu.layout");
Здесь происходит загрузка расположения элементов интерфейса. (кнопки, окошки и т.п.) Можно конечно было создать все кнопки вручную, но гораздо удобнее хранить их расположение в отдельном xml-файле. Ниже покажу его содержимое:
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="Window" position="600 450 365 256" layer="Main" name="MainMenu">
<Property key="Widget_Caption" value="#{TXT_MAIN_MENU}"/>
<Property key="Widget_Alpha" value="0.8"/>
<Widget type="Button" skin="Button" position="10 10 150 30" align="ALIGN_DEFAULT" name="StartButton" >
<Property key="Widget_Caption" value="#{TXT_START_GAME}" />
</Widget>
<Widget type="Button" skin="Button" position="10 50 150 30" align="ALIGN_DEFAULT" name="ResumeButton" >
<Property key="Widget_Caption" value="#{TXT_RESUME_GAME}" />
</Widget>
<Widget type="Button" skin="Button" position="10 90 150 30" align="ALIGN_DEFAULT" name="SettingsButton" >
<Property key="Widget_Caption" value="#{TXT_SETTINGS}" />
</Widget>
<Widget type="Button" skin="Button" position="10 130 150 30" align="ALIGN_DEFAULT" name="ExitButton" >
<Property key="Widget_Caption" value="#{TXT_EXIT}" />
</Widget>
</Widget>
</MyGUI>
В нем мы описываем расположение одного окна и кнопок управления в нем.
После того, как все элементы интерфейса загружены, мы получаем указатель на созданное окно меню и располагаем его посередине, в зависимости от текущего разрешения экрана.
MyGUI::IntSize view = _app->GetGui()->getViewSize();
MyGUI::WidgetPtr window = _app->GetGui()->findWidget<MyGUI::Widget>("MainMenu");
window->setPosition(view.width/2 - window->getWidth()/2, view.height/2 - window->getHeight()/2);
После этого создаем и присоединяем к нему контроллер, благодаря которому окошко будет постепенно проявляться на экране. Это просто для красоты :)
MyGUI::IntSize view = _app->GetGui()->getViewSize();
MyGUI::WidgetPtr window = _app->GetGui()->findWidget<MyGUI::Widget>("MainMenu");
window->setPosition(view.width/2 - window->getWidth()/2, view.height/2 - window->getHeight()/2);
Затем указываем обработчик событий всех кнопок. Как я уже указывал, он будет один. А определять от какой кнопки пришло сообщение, мы будем уже в нем.
MyGUI::ButtonPtr button = _app->GetGui()->findWidget<MyGUI::Button>("ExitButton");
button->eventMouseButtonClick = MyGUI::newDelegate(this, &Game::MainMenuDelegate);
button = _app->GetGui()->findWidget<MyGUI::Button>("StartButton");
button->eventMouseButtonClick = MyGUI::newDelegate(this, &Game::MainMenuDelegate);
button = _app->GetGui()->findWidget<MyGUI::Button>("SettingsButton");
button->eventMouseButtonClick = MyGUI::newDelegate(this, &Game::MainMenuDelegate);
Ну а в самом конце, укажем в каком состоянии находится сейчас наша игра:
_state = GAME_STATE_MAIN_MENU;
Все, теперь можно компилировать. Если вы ничего не забыли, то должна получиться вот такая картинка:

Прикрепляю также исходные файлы этого проекта tutorial02.zip.
Добавить комментарий
Заполните форму ниже для добавления ваших комментариев