Sign in to follow this  
Unwise owl

Connecting UI Code with Game Code

Recommended Posts

I've programmed the early stages of a fairly typical tree-based UI for my game. That is, for every parent window there are child windows (that can be derived sub classes for buttons etc.), and when I call render and collision detection functions(click point test) these recursively down the tree (collision detection front to back and rendering back to front). Now, I run into a problem regarding events. I know how to make them, but I don't know what object should be responsible for 1) generating the events, that is, checking for clicks and triggering events, and 2) how to execute certain game code based on what event happened to which window. To solve the former problem I guess I could let the cursor code invoke click events, but that means it will have to know about what part of the UI is active at the moment. (There are two distinct states: "Menu" and "playing".) I have a menu object; I could let it deal with it, but that'd require to have a similar object for the actual game. Perhaps I should consider creating a "CPlaying" or "CGame" object and let it and "CMenu" derive from a base class that has functions that the main loop can call if there was input? To solve problem nr. 2, I was thinking of having a "CAction" class that would be derived for each action that can be trigger by an UI event. There would be some sort of central registry (perhaps one for CMenu for example) where they were linked to an event key. Once an event triggers it would look into this registry and execute a virtual function in the CAction pointed to. I see multiple potential dependency clashes here though. Comments?

Share this post


Link to post
Share on other sites
I've used something like this in the past.

For #1, I didn't have an object handle it. Input was garnered, and then a function walked the tree and did mouse hit detection [or keybinding detection] on the different renderables. The renderables themselves store the event(s), which is triggered by the function if the input matches.

In a little more detail, I use boost::functions for the stored events. This simplifies things greatly, and allows the input handling to effectively ignore what it's triggering.

Which goes right into #2. For game code, you just specify game functions as the trigger. When creating a ship renderable, something like this would occur.

image ship_image; // UI only code
ship player_ship; // game only code

initialize_ship(&ship_image, player_ship); // mixed code. make the image the ship
// and use the game code to place it
// at the right spot.

// Also, this would likely be in that initialization function:
ship_image.bind(KB_SPACE, boost::bind( &ship::fire_lasers, player_ship, _1 ) );
ship_image.bind(KB_CTRL, boost::bind( &ship::fire_engines, ...




As long as the ship is the top rendered object with those keys bound, pressing them will do the expected game effect. Doing text input is a little trickier :]

That's what I've done in the past, and it worked pretty well. There is of course many ways of doing this sort of thing, and this might not be the best way for your situation [or even mine for that matter...].

Share this post


Link to post
Share on other sites
I'll have to look up Boost, I see it frequently around here.

Am I correct in that boost::bind is a global function registry? Interesting, but it makes sense because one registry is really only needed...

Share this post


Link to post
Share on other sites
ah no, boost::bind is a function binding thing. In the above code it converts

player_ship.fire_lasers();

into something that fits into a function pointer to a void function() but calls player_ship.fire_lasers() when triggered.

image::bind takes the enumeration/boost::function pair and just puts it into a std::map stored with the renderable. Actually stored with an input handler class, which renderables inherit from, but that's just implimentation detail...

Anyways, that map is not a global registry, just a per renderable one.

Share this post


Link to post
Share on other sites
Ok, I've decided to throw out the damn CAction base class attempt and do it with mapped function pointers instead like in your example, with or without Boost (as of yet undecided). Having a class for each command just becomes incredibly cumbersome since the action should have complete knowledge of the class it's supposed to modify. Referring to a member function seems like a much more pretty solution.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this