Menu Implementation.

Started by
4 comments, last by Captain P 13 years, 7 months ago
Hi!
I've to design a Menu System. My initial menu page should have 4 buttons. If I click any one of the buttons, a new menu page has to load with some other elements(buttons). At present I've coded the class for initial Menu page and the class for one of the Buttons. I'm creating the device inside main() function, and instantiate my intial menu class. Also I called the game loop function for initial menu page from main() function. Now my problem is, I've to pass the device to the second class from the first class from the OnEvent function. i.e How to communicate between classes?
Advertisement
I'm not quite sure what the problem is, but I'll briefly explain how I did my rendering/game loop.

In my case I had two different modes, or scopes. the game could be in, Game or Menu. Instead of passing the Device around, I just have it as a single static member, and the render method doesn't get called unless the device is functioning.

What I did was have a base engine class with all static members. Then each "Scope" of the game is known by the base engine class. The base engine class also contains the graphics Device. The rendering loop calls a method in the base engine, which calls the render method on the currently active Scope.
I usually use a Screen class as base-class for all my screens and menus. My main game loop contains a reference to the currently active Screen object. The Screen class (actually, it mostly serves as an interface) exposes update and input handling functions, which the main loop can call.

Pseudo-code example:
class Game{    Screen *activeScreen;    void setActiveScreen(Screen* screen)    {        // Game takes ownership of the active screen, so it removes the old one.        // You may want to be more careful than this, however: the old screen        // likely called this function, so you may not want to delay it's        // destruction until the next main loop cycle.        delete activeScreen;        activeScreen = screen;    }    void run()    {        while(running)        {            handleEvents();            update();            draw();        }    }    void handleEvents()    {        if(user pressed key)            activeScreen->keyPressed(key);        else if(user released key)            activeScreen->keyReleased(key);        // Mouse input, etc.    }    void update()    {        activeScreen->update(delta);    }    void draw()    {        // I usually handle drawing with a separate system, but oh well.        activeScreen->draw(surface);    }};class Screen{    // You'll probably want a pointer to the 'screen manager', so a screen    // can easily transfer control to another screen.    Game* game;    virtual void keyPressed(Keycode key);    virtual void keyReleased(Keycode key);    virtual void update(double delta);    virtual void draw(Surface& surface);};

In this case, your menu would derive from Screen, and implement the various functions with menu-specific code. When it's time to move to the next menu, it would create an instance of that menu's class and set it as the active screen.

You could also keep a stack of screen objects - going back to a previous screen would then be a matter of popping the top screen. Alternately, you could create all screen objects at startup, and provide a showScreen(ScreenType type) function instead of setActiveScreen, using an enumeration to look up screens. In both cases, you may want to add screenDidBecomeActive and screenDidBecomeInactive functions to your Screen class.

Objects that need to be known by multiple screens could be placed in the Game class, such as a Settings object, or a SoundEngine or Renderer. I would advise against using static members, due to certain issues (instantiation order, for example, and global accessibility, which often leads to sloppy design).
Create-ivity - a game development blog Mouseover for more information.
Hi!
I've got to work the new window. If I click the Options Button, new window opens with gui elements. But event is not triggering for the buttons in the new window. This is my code:

The InitialMenu class:

 #include <irrlicht.h> #include "../include/InitMenu.h" #include "../include/OptionsMenu.h" using namespace irr; using namespace core; using namespace video; using namespace gui; using namespace io; using namespace scene; class COptionsMenu; InitEventReceiver::InitEventReceiver(SInitMenuContext &context):initMenuContext(context) { } bool InitEventReceiver::OnEvent(const irr::SEvent& event) {  if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)  {   s32 idBtn = event.GUIEvent.Caller->getID();   switch(idBtn)   {    case PLAY_BUTTON:       return true;       break;    case OPTIONS_BUTTON:       {        COptionsMenu *optMNU = new COptionsMenu();       optMNU->runGame();       initMenuContext.device->closeDevice();       return true;       break;       }    case CREDITS_BUTTON:       return true;       break;    case EXIT_BUTTON:       initMenuContext.device->closeDevice();       break;       return true;    default:       return false;   }   return true;  }  return false; } CInitMenu::CInitMenu() {  IrrlichtDevice* device = createDevice(video::EDT_DIRECT3D9,core::dimension2d<u32>(640,480),16,false,false,false,0);  dev = device;  int width = 180;  int height = 50;  int x = (device->getVideoDriver()->getScreenSize().Width - 200)/2;  int y = 100;  SColor WHITE = video::SColor(255,255,255,255);  SColor BLUE = video::SColor(255,0,0,255);  gui::IGUISkin* skin = device->getGUIEnvironment()->createSkin(EGUI_SKIN_TYPE::EGST_WINDOWS_METALLIC);  skin->setColor(gui::EGDC_BUTTON_TEXT,WHITE);  skin->setColor(gui::EGDC_WINDOW,BLUE);  device->getGUIEnvironment()->setSkin(skin);  device->getSceneManager()->loadScene("Data/experimentalMenuSystem/Shop.irr");  device->getSceneManager()->addCameraSceneNode(0,core::vector3df(0,100,0),core::vector3df(0,0,100),-1,true);  m_pPlayButton = device->getGUIEnvironment()->addButton(core::recti(x,y,x+width,y+height),0,PLAY_BUTTON,L"Play");  y = y+height;  m_pOptionsButton = device->getGUIEnvironment()->addButton(core::recti(x,y,x+width,y+height),0,OPTIONS_BUTTON,L"Options");  y = y+height;  m_pCreditsButton = device->getGUIEnvironment()->addButton(core::recti(x,y,x+width,y+height),0,CREDITS_BUTTON,L"Credits");  y = y+height;  m_pExitButton = device->getGUIEnvironment()->addButton(core::recti(x,y,x+width,y+height),0,EXIT_BUTTON,L"Exit");  initMnuContext.device = device;  initMnuContext.m_pPlayButton = m_pPlayButton;  initMnuContext.m_pOptionsButton = m_pOptionsButton;  initMnuContext.m_pCreditsButton = m_pCreditsButton;  initMnuContext.m_pExitButton = m_pExitButton; } int main(int argc, char **argv) {  CInitMenu* cIMNU = new CInitMenu();  cIMNU->runGame(); } void CInitMenu::runGame() {  InitEventReceiver initReceiver(initMnuContext);  dev->setEventReceiver(&initReceiver);  while(dev->run())  {   if (dev->isWindowActive())   {    dev->getVideoDriver()->beginScene(true, true, video::SColor(0,200,200,200));    dev->getSceneManager()->drawAll();    dev->getGUIEnvironment()->drawAll();    dev->getVideoDriver()->endScene();   }  }  dev->drop(); }


The options Menu class:

#include <irrlicht.h> #include "../include/OptionsMenu.h" #include "../include/InitMenu.h" //CInitMenu cIMNU; using namespace irr; using namespace core; using namespace video; using namespace gui; using namespace io; using namespace scene; OptionsEventReceiver::OptionsEventReceiver(SOptionsContext &optionsContext):OptionsContext(optionsContext) { } bool OptionsEventReceiver::OnEvent(const irr::SEvent& event) {  if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)  {   s32 idBtn = event.GUIEvent.Caller->getID();   printf("Button Clicked: %d \n",idBtn);   switch(idBtn)   {    case PROFILE_BUTTON:       return true;       break;    case FAVOURITES_BUTTON:       return true;       break;    case MATCH_RESULT_BUTTON:       return true;       break;    case  OPTIONS_BACK_BUTTON:       {        CInitMenu *cInitMNU  = new CInitMenu();       cInitMNU->runGame();       OptionsContext.device->closeDevice();        return true;       break;       }    default:        return false;   }   return false;  } } COptionsMenu::COptionsMenu() {  IrrlichtDevice* device = createDevice(video::EDT_DIRECT3D9,core::dimension2d<u32>(640,480),16,false,false,false,0);  dev = device;  int width = 180;  int height = 50;  int x = (device->getVideoDriver()->getScreenSize().Width - 200)/2;  int y = 100;  SColor WHITE = video::SColor(255,255,255,255);  SColor BLUE = video::SColor(255,0,0,255);  gui::IGUISkin* skin = device->getGUIEnvironment()->createSkin(EGUI_SKIN_TYPE::EGST_WINDOWS_METALLIC);  skin->setColor(gui::EGDC_BUTTON_TEXT,WHITE);  skin->setColor(gui::EGDC_WINDOW,BLUE);  device->getGUIEnvironment()->setSkin(skin);  device->getSceneManager()->loadScene("Data/experimentalMenuSystem/Shop.irr");  device->getSceneManager()->addCameraSceneNode(0,core::vector3df(0,100,0),core::vector3df(0,0,100),-1,true);  m_pPlayerProfileButton = device->getGUIEnvironment()->addButton(recti(x,y,x+width,y+height),0,PROFILE_BUTTON,L"Player Profile");  y = y+height;  m_pFavouritesButton = device->getGUIEnvironment()->addButton(recti(x,y,x+width,y+height),0,FAVOURITES_BUTTON,L"Favorites");  y = y+height;  m_pMatchResultButton = device->getGUIEnvironment()->addButton(recti(x,y,x+width,y+height),0,MATCH_RESULT_BUTTON,L"Match Result");  m_pOptionsBackButton = device->getGUIEnvironment()->addButton(recti(0,400,192,458),0,OPTIONS_BACK_BUTTON,L"Back");  optionsContext.device = device;  optionsContext.m_pPlayerProfileButton = m_pPlayerProfileButton;  optionsContext.m_pFavouritesButton = m_pFavouritesButton;  optionsContext.m_pMatchResultButton = m_pMatchResultButton;  optionsContext.m_pOptionsBackButton = m_pOptionsBackButton; } void COptionsMenu::runGame() {  OptionsEventReceiver optReceiver(optionsContext);  dev->setEventReceiver(&optReceiver);  while(dev->run())  {   if (dev->isWindowActive())   {    dev->getVideoDriver()->beginScene(true, true, video::SColor(0,200,200,200));    dev->getSceneManager()->drawAll();    dev->getGUIEnvironment()->drawAll();    dev->getVideoDriver()->endScene();   }  }  dev->drop(); } 


What to do trigger the events for options Menu and to open the options Menu in the single window(not in a separate window)?
Hi!
I solved the Events not triggering problem. I forgot this statement:

return false;


at the OnEvent() function of OptionsMenu Class. Can any body help me to open the Options Menu in a single window? I'm creating device(windows) at the constructor of each class. What to do to create single device and use it for both the classes? How to restructure my tow classes?
Your device needs to be shared across various screens, so obviously it shouldn't 'live' in any of these screens. Instead, create it outside these screens (for example, in your main() function), and pass a reference or pointer to it to your screens: InitMenu::InitMenu(IrrlichtDevice* device)
Create-ivity - a game development blog Mouseover for more information.

This topic is closed to new replies.

Advertisement