[resolved] creating menu system for a game

For help with general CEGUI usage:
- Questions about the usage of CEGUI and its features, if not explained in the documentation.
- Problems with the CMAKE configuration or problems occuring during the build process/compilation.
- Errors or unexpected behaviour.

Moderators: CEGUI MVP, CEGUI Team

duindain
Just popping in
Just popping in
Posts: 19
Joined: Sat Jun 09, 2007 08:51

[resolved] creating menu system for a game

Postby duindain » Sat Jun 09, 2007 21:09

Hey ive got a couple of questions

im creating a menu for a uni project i currently use the demo7 as the base code
ive created about 8 full windows inside the layout xml document each window contains different buttons and text areas some contain pictures and other widget thingys

question 1

whats the most efficent way of swapping menu windows currently i set all except 1 menu as invisible on startup then switch the new menu to visible and the previous to invisible would it be better to have only one window and somehow dynamically create the buttons and text areas from a file with new content or load all at the start as it is currently and use setVisible

question 2

is there a way to set a global subscribe event to the root window so i dont have to create seperate event calls for every single button im currently using code from the forums for event calls or at the very least create an event call one level higher than the button so it handles all the buttons for that menu window

this is the forum posts i found the single function event handler code from

http://www.cegui.org.uk/phpBB2/viewtopi ... ght=button
and
http://www.cegui.org.uk/wiki/index.php/ ... e_Callback

but these only confine the event calls to one function they dont fix the problem of having to set the same event to every single button
this is a problem because i have about 25 buttons in total

any help is appreciated thankyou
Last edited by duindain on Mon Jun 11, 2007 18:02, edited 2 times in total.

Rackle
CEGUI Team (Retired)
Posts: 534
Joined: Mon Jan 16, 2006 11:59
Location: Montréal

Postby Rackle » Sun Jun 10, 2007 13:37

>> whats the most efficent way of swapping menu windows

It depends on the number of menu windows you have. If there's 100-500 then loading each one, even if invisible, would take up too many resources (memory) unnecessarily. Instead you'd be better off loading a single menu window at a time, destroying it (it's widgets and subscribed events) and loading a new menu window. But with this approach you now have to deal with disk access, which may cause unwanted pauses.

If you're reading from a hard disk then access is pretty fast, but if your resources are on a DVD or accessed through a network, then this slowdown may be unacceptable. An alternative would be to load a current menu and in background (another thread) load every menu that could be started from this current one).


>> is there a way to set a global subscribe event

Have a look at Cool_window_effects for an example of global events. With this approach you subscribe to the pushbutton click event and within the function handler you query the name of the button that triggered the event:

Code: Select all

bool onButtonClicked(const EventArgs& e)
{
  const WindowEventArgs& we = static_cast<WindowEventArgs&>(e);
  we.window->getName()
}


What I dislike with this approach is that every single pushbutton will pass through this function. If you have another pushbutton to be used for a different purpose then you'll have to write special code. Here's what I like better:

Code: Select all

class MyClass
{
  void subscribeMenuButton(const String& pName)
  {
    Window* menuButton = WindowManager::getSingleton().getWindow(pName);
    menuButton->subscribeEvent(PushButton::Event::Clicked, Event::Subscriber(&MyClass::onMenuButton, this));
  }
  bool onMenuButton(const EventArgs& e)
  {
    const WindowEventArgs& we = static_cast<WindowEventArgs&>(e);
    we.window->getName()
    // Process the action of this menu button
  }
}


You'd call subscribeMenuButton() with every menu button and then code the appropriate response within onMenuButton(). It's still sloppy but seems safer.

You could also create 25 classes, 1 class per behavior:

Code: Select all

class MenuButton
{
public:
  void subscribe(const String& pName)
  {
    Window* menuButton = WindowManager::getSingleton().getWindow(pName);
    menuButton->subscribeEvent(PushButton::Event::Clicked, Event::Subscriber(&MenuButton::onMenuButton, this));
  }
  bool onMenuButton(const EventArgs& e)
  {
    onMenu();
  }
  virtual void onMenu() = 0;
};

class MenuButtonA : public MenuButton
{
public:
  void onMenu()
  {
    // Perform the action
  }
};

class MenuButtonB : public MenuButton
{
public:
  void onMenu()
  {
    // Perform the action
  }
};


If you have a lot of code handling each button then this approach may be cleaner. Another approach would be to use 25 different functions within a single class:

Code: Select all

class MyClass
{
  void subscribeMenuButtons
  {
    Window* menuButton = WindowManager::getSingleton().getWindow("MenuButton1");
    menuButton->subscribeEvent(PushButton::Event::Clicked, Event::Subscriber(&MyClass::onMenuButton1, this));
    Window* menuButton = WindowManager::getSingleton().getWindow("MenuButton2");
    menuButton->subscribeEvent(PushButton::Event::Clicked, Event::Subscriber(&MyClass::onMenuButton2, this));
  }
  bool onMenuButton1(const EventArgs& e)
  {
    // Process the action of this menu button
  }
  bool onMenuButton2(const EventArgs& e)
  {
    // Process the action of this menu button
  }
}


Note: none of this code has been tested.

duindain
Just popping in
Just popping in
Posts: 19
Joined: Sat Jun 09, 2007 08:51

thankyou for the advice

Postby duindain » Mon Jun 11, 2007 17:42

ive ended up implementing the buttons as a vector of strings that i implement in a for loop to set the callbacks then just using if statements in the single callback system as follows

Code: Select all

void Demo7Sample::initDemoEventWiring(void)
{
    using namespace CEGUI;

vector<string> buttons;

   buttons.push_back("multiplayer"),
   buttons.push_back("newgameback"),
   buttons.push_back("newgamedifficultyback");
   
for(unsigned int index = 0; index<buttons.size();index++)
   {
      WindowManager::getSingleton().getWindow(buttons[index])->
        subscribeEvent(PushButton::EventClicked, Event::Subscriber(&Demo7Sample::handleButtonClick, this));
   }
}


Code: Select all

bool Demo7Sample::handleButtonClick(const CEGUI::EventArgs& e)
{
   using namespace CEGUI;
   
   const CEGUI::WindowEventArgs& we =
      (const CEGUI::WindowEventArgs&) e;

   string senderID = we.window->getName().c_str();
   if(senderID == "quit")
      handleQuit(e);
   if(senderID == "newgame")
      swapWindows("newgamewindow","defaultwindow");
   if(senderID == "loadgame")
      swapWindows("loadgamewindow","defaultwindow");
return true;
}


ive removed the majority of the buttons and if statements to make this post less lengthy i didnt make all this for 3 buttons heh

im using 8 windows at the moment im using the setvisible to swap between them it seems to work great

thankyou for your help

Rackle
CEGUI Team (Retired)
Posts: 534
Joined: Mon Jan 16, 2006 11:59
Location: Montréal

Postby Rackle » Mon Jun 11, 2007 19:03

I forgot to mention another way. After you have loaded a .layout you can recursively go through every child and test whether it is a pushbutton. You can then subscribe that pushbutton. This way you automatically detect new buttons in the layout. And in the handleButtonClick() function you can code a default action of displaying a "This button has not been configured yet" message.


Return to “Help”

Who is online

Users browsing this forum: Baidu [Spider] and 9 guests