Page 1 of 1

subscribeEvent and arguments

Posted: Mon Mar 21, 2011 12:02
by ravak_
I am working on a turn-based strategy game using a grid interface to control the units (ala Advance Wars, Civilization). All told, I have three hundred tiles available for the user to click on. I have a two-dimensional array to track where the units are, and when I click on one of the tiles with a unit on, I want to be able to start issuing various commands.

Each tile is implemented using the following function:

Code: Select all

void TutorialApplication::createTile(int x, int y, CEGUI::Window *parent) {
   CEGUI::WindowManager &wgmr = CEGUI::WindowManager::getSingleton();
   Ogre::String s = Ogre::String("(" + Ogre::StringConverter::toString(x) + ", " + Ogre::StringConverter::toString(y) + ")");

   CEGUI::Window *w = wgmr.createWindow("DefaultWindow", s);
   w->setPosition(CEGUI::UVector2(CEGUI::UDim((x-1)/20.0f, 0), CEGUI::UDim((y-1)/15.0f, 0)));
   w->setSize(CEGUI::UVector2(CEGUI::UDim(0.05f, 0), CEGUI::UDim(0.0666f, 0)));
   w->setText(s);
   w->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&TutorialApplication::overlayTileClick, this));

   parent->addChildWindow(w); }


The problem is I can't determine what tile I clicked using the subscribeEvent() function. I was hoping that I could do something like this...

Code: Select all

w->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&TutorialApplication::overlayTileClick(x, y), this));

...but then I get a lovely C2661 error: 'CEGUI::SubscriberSlot::SubscriberSlot' : no overloaded function takes 2 arguments

Is it possible to add arguments in this way, so I can determine what tile has been selected? Or is there another / better way to implement what I'm looking for - that is, a way to know what tile was clicked.

Thanks,
-- Rav

Re: subscribeEvent and arguments

Posted: Mon Mar 21, 2011 12:54
by IrmatDen
Hi,

To extract the tile, you might consider storing a vector<TileDef*> in your class, where TileDef is a struct defining the tile's content (currently, the position only). Then set the Window's userdata pointer to the matching TileDef instance; something like this:

Code: Select all

struct TileDef {
   int x, y;
};
typedef std::shared_ptr<TileDef> TileDefPtr;

typedef std::vector<TileDefPtr> GameTilesContainer;
GameTilesContainer gameTiles;

void TutorialApplication::buildGameTiles() {
   gameTiles.swap(GameTilesContainer());
   gameTiles.reserve(endX * endY);

   TileDefPtr tile;
   for (int x = 0; x != endX; x++)
   {
      for (int y = 0; y != endY; y++)
      {
         tile = TileDefPtr(new Tile(x, y));
         gameTiles.push_back(tile);
      }
   }
}

void TutorialApplication::createTile(int x, int y, CEGUI::Window *parent) {
   CEGUI::WindowManager &wgmr = CEGUI::WindowManager::getSingleton();
   Ogre::String s = Ogre::String("(" + Ogre::StringConverter::toString(x) + ", " + Ogre::StringConverter::toString(y) + ")");

   assert(x < endX);
   assert(y < endY);
   TileDefPtr matchingTile = gameTiles.at(x * endX + y);

   CEGUI::Window *w = wgmr.createWindow("DefaultWindow", s);
   w->setPosition(CEGUI::UVector2(CEGUI::UDim((x-1)/20.0f, 0), CEGUI::UDim((y-1)/15.0f, 0)));
   w->setSize(CEGUI::UVector2(CEGUI::UDim(0.05f, 0), CEGUI::UDim(0.0666f, 0)));
   w->setText(s);
   w->setUserData(matchingTile.get());
   w->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&TutorialApplication::overlayTileClick, this));

   parent->addChildWindow(w);
}


Then, make your overlayTileClick takes no arguments, except for the WindowEventArgs&. From the args received, get the event's source Window pointer by casting EventArgs to WindowEventArgs, and extract the TileDef pointer with Window::getUserData.

Two side-related things though:
1. You're suscribing to the wrong argument: your window is a CEGUI::Window, not a CEGUI::PushButton. You want to suscribe to Window::EventMouseClick
2. I really am not convinced that using CEGUI Windows to represent tiles is efficient. You have a lot of useless overhead for a tilemap.

Re: subscribeEvent and arguments

Posted: Mon Mar 21, 2011 13:06
by Kulik
You can use either boost::bind or something similar to bind the 2 arguments or just use WindowEventArgs::window to figure out what windows has been clicked.

Re: subscribeEvent and arguments

Posted: Mon Mar 21, 2011 13:18
by ravak_
Potentially realised in the interim that I don't need three hundred tiles, nor do I need to track their location. Using a single window, I can just get the position of mouse, and calculate what tile I'm clicking on from there. I think this potentially answers the second point IrmatDen made.

As for the first point, thank you. I was wondering why I wasn't getting much of a response.

Re: subscribeEvent and arguments

Posted: Mon Mar 21, 2011 13:37
by IrmatDen
ravak_ wrote:Potentially realised in the interim that I don't need three hundred tiles, nor do I need to track their location. Using a single window, I can just get the position of mouse, and calculate what tile I'm clicking on from there. I think this potentially answers the second point IrmatDen made.

Since you're using Ogre, I would use either of those solutions of derive the (x,y) tile coord the user clicked:
* a simple invisible plane at world level 0
* the level mesh
(It all depends on how you're planning your game to appear, like, if you have interactive high mountains or deep "holes" (ocean, canyons etc...), the first solution might not fit the user's expectations.)