PDA

View Full Version : best way to do a GUI (re: region hovers?)



wazoo
11-20-2004, 07:27 PM
Hey all,

I'm getting my actual game working, but need to put together the GUI system. I've got some images for buttons, etc. and I'm just checking here as to if I'm doing it (more or less) the "right" way....

All I was thinking of getting to work, was defining RECT areas for my button images...then when my game state is in a menu mode, every frame pings the mouse position to find out which RECT area it's in....then either display the regular button image or the "selected" button image when appropriate..

Is this what everyone else is doing with their GUI's or is there another way I'm just not thinking about here??

thanks in advance!

Pyabo
11-21-2004, 03:07 AM
Sorry I don't have an answer for you... but I wanted to chime in on this thread and just say that that is a damn good question. :)

I'm also curious what the "correct" way to implement GUIs is. The code I write for this always feels like a complete hack to me. I guess this is why Windows does it all for you in regular Win32 apps. When are we going to get a native DirectX GUI framework? Hmmmm.

cliffski
11-21-2004, 03:53 AM
thats pretty much what I've always done. You should have a hierarchical GUI if you use a lot of windows, so that a button only checks its gui state if its parent window has the cursor within it etc. Much faster that way.

hodo
11-21-2004, 05:08 AM
Huge subject there. Most people dont consider the GUI but it is one of the most important parts of the game.
There are lots of ways to do it and it all depends on how many buttons you have to deal with but here is one I use.
A GUI panel that has buttons in it or "Dialog box" you can to a point in rect on the outer boxes for fast test then if any test succeeds do a point in rect on all the elements in the box to see which one the mouse is over then display the correct graphic. So make an immaginary box around groups of buttons or clusters and you can do a fast test that way. Other elements like sliders, edit boxes etc need programmed for each action but the fast is the point in rect trick.
Big problem in logic you will have is on every time through the render loop things like Is the button down while the pointer is over the box, Was the button already down from last time. Was the button up before it went down or was it still down. That kind of stuff will drive you mad.

milo
11-21-2004, 09:45 PM
@wazoo -

Well, that's a good start. One thing that you should consider is how the various dialog boxes (or full screen windows) will need to react to button clicks and list selections and so on. When the user clicks the "Start" button, you need to do more than just change the button image. You also need to call whatever function is necessary to start the game.

I found that I needed something a bit more elaborate than what you have described. I created a complete GUI window library in the generic game engine layer. Windows are rectangular areas of the game screen, and have a list of Views that draw content into the window's client area. Active Windows are GUI widgets - they are derived from the Window base class, but also know how to draw themselves and how to respond to user events.

All of the GUI widget classes implement an "Event Target" interface with callbacks like "OnMouseEnter" and "OnLButtonDown" and so on. There is an "Event Dispatcher" singleton that processes the mouse and keyboard inputs, manages key focus, and calls the callback functions through the Event Target interface.

Each type of widget intercepts the event callback to handle specific rendering chores, and then passes the call to any other object that has expressed an interest in the event. The game-specific dialogs use some simple macros to register their member functions as being interested in the callbacks. As a simple example, a dialog could intercept the "OnMouseEnter" and "OnMouseExit" events in order to implement roll-over help.

This is basically the same method that is used in both MFC and the old Borldand OWL library. It works very well, but of course it isn't the only way to get the job done. I'm just trying to give you some ideas of the kinds of problems that you will need to design solutions for.

Good luck,

Vectrex
11-21-2004, 10:10 PM
this is why i'm really interested in embedding some type of flash player in my program. If i could do that id be able to have all the gui's up and running in days , not weeks and they'd be loads funkier :) Gameswf seems like a candidate. crazy eddies gui system seems great too

Mark Sheeky
11-22-2004, 12:47 AM
I think the trick is to make the GUI code as event based as possible. An icon class with a rect area and such functions as 'mouse on', 'mouse off', 'left click' etc. Makes it really easy to do a basic GUI. A separate definition of icon types and locations is useful too and would allow you to design and change different looks/hover glows/sizes of icons easily.

Mark
Sound Effects For Game Developers
http://www.indiesfx.co.uk

wazoo
11-22-2004, 03:36 AM
Thanks for the feedback all,

I know that the DX9.0c SDK comes with a GUI system which seems to hook
itself into your windows callback methods, but I was hoping to get a GUI going with something a little bit older...ie. DX8.1.

@cliffski: thanks. I guess it does depend upon how much interaction your game has with a player. If it's just for things like "start game" and "buy me", then rolling a few buttons and checking RECTs is probably going to be ok.

@milo: Nice suggestions, and well done on creating a "proper" sounding GUI framework. If/when I need something more elaborate than some buttons, that might be the way I'm gonna have to go. I think there's a HUGE reason why barely any games use a TextEdit widget...;)

Not that it's the "final" solution, but I'm gonna try and sift through some commercially available sourcecode (ie. Quake2, Freespace2, etc) to see if I can figure out how they did it...(for something more than buttons)..

luggage
11-22-2004, 06:58 AM
I don't find the GUI stuff all that difficult.

I start off writing a Window object, and the data is loaded from a text file. So I'd have...

mainMenu = Window_Load( "data\gui\mainmenu.txt" );

Then update and render it with Window_Update( mainMenu, delta ); and Window_Render( mainMenu );

Inside the window_load function it parses the text file for whatever I have in it. It might look like

BEGIN CLICKBUTTON
ID=1
IMAGES="data\images\quit\"
POSITION=20,20
FUNCTION="MainMenu_Quit"
END

BEGIN IMAGE
IMAGES="data\images\logo.png"
POSITION=400,400
END

It's easy enough to parse and as I add more widget types you'd just have BEGIN EDITBUTTON and so on. The images section for click button in the example points to a directory. Inside that would be an image for each state if needed, ie. on.png, off.png, invalid.png. All positions are offsets to the window position (there's a Window_SetPosition call ). This way you can drag windows around and what not.

The function parameter is the callback in code to call when the button is clicked. The function gets passed a lpClickButton structure and inside that you can check the id to make sure it's a particular button (or just call an individual function per button). So something like.


void MainMenu_Quit( lpClickButton button )
{
Game_Quit();
}

or if you don't want loads of callbacks you can just use 1 for each type of button the way I've done it.


void MainMenu_ClickButtonCallback( lpClickButton button )
{
case button->id
{
case 1: // quit button pressed
break;

}
}

That's pretty much it. In the Windows Update I call the ClickButton_Update for each clickbutton. In that it gets the mouse position, checks to see if it's inside the image, if the button has been pressed process it and call the required function.

I've looked at a few Gui libraries but most of them aren't that friendly for using your own images so it's difficult to get away from the original style.

Hope all that helps

scott

milo
11-22-2004, 08:27 AM
@luggage -

Interesting. I do something similar wrt parsing a text definition of each screen. In the newest version of my library I'm using a constraint based grid to handle layout of the controls at runtime instead of specifying exact screen coordinates. That way I can have a single screen definition that works in all fullscreen resolutions and arbitrary window sizes.

Question: how do you map the FUNCTION="MainMenu_Quit" declaration into a runtime call to an actual C/C++ function? Do you have some C/C++ code that registers all your callbacks in a dictionary?

--milo
http://www.starshatter.com

Hiro_Antagonist
11-22-2004, 08:59 AM
Hey there,

For what it's worth, I think it's pretty important that you have a system that at least loosely emulates Windows form controls.

For our game, I created a base UIControl class, as well as a UIControlContainer class. I then derive all of my individual UI control classes (textboxes, textareas, select boxes, scrollbars, checkboxes, etc.) from that core class.

The UIControl base class has virtual definitions for Draw(), ProcessMouse(), and ProcessKeyboard() that I can override with the specific behavior for each class.

Then, as appropriate, I use delegates to set up events that the UIControls fire. (OnClick, OnChange, etc.)

The constructor takes many parameters for each UIControl class, with the common ones being stuff like xLocation, yLocation, width, height, etc. I had put a rudamentary focus system in place, and I was starting to get around to an event bubbling solution when I ended up switching to someone else's engine/framework.

I was surprised that the new framework we recieved uses almost exactly the same approach, though it's far better evolved. (They also have an Update() function in addition to the others, for distinct per-frame logic handling.)

I personally feel that a well-developed UI solution is *invaluable*. Keep in mind that you should write these UI control classes to be independant from your game, so that you can use them in all of our future games.

My rule of thumb is that almost half of the time writing your first game should be spend towards common code, to be used in future games. UI controls should represent a fairly large percentage of that work.

I'm more than willing to share my UIControl code (which is written in C#) if you think it would help you, especially since we've had to abandon it when we moved to C++.

-Hiro_Antagonist

luggage
11-22-2004, 09:34 AM
What I do with function callback is...



#define REGISTERFUNCTION(name) FunctionList_AddFunction( name, #name)

VOID FunctionList_AddFunction( void (*func)(pClickbutton button), char *name )
{
// in here add the function pointer and the name pair to a list
// you can search through the list when parsing the text files to find the correct function pointer
}



Then before you start parsing text files you need to do...


REGISTERFUNCTION( MainMenu_Quit );

for each function you want your text files to be able to call.

You can probably do something a bit similar to windows where you have 1 callback for each window. Pass it the pointer to the window structure, a message, and the WPARAM, LPARAM for data and just let the messaged define how to cast them.

Scott

luggage
11-22-2004, 09:41 AM
What we do for different screen resolutions is use one base resolution for everything and then use a macro to convert coords and sizes. n

Some work we do is for machines that can't resize the artwork realtime so we just specify different sets for the different resolutions. So there'd be a 640x480, 800x600, 1024x768 and it uses the correct data accordingly.

EpicBoy
11-22-2004, 09:57 AM
What we do for different screen resolutions is use one base resolution for everything and then use a macro to convert coords and sizes. n
That's what I do as well. All UI drawing code draws to a virtual 640x480 screen and the vertices are automatically scaled to fit whatever resolution is currently being used.

wazoo
11-22-2004, 10:01 AM
Those are some great ideas guys! thanks a lot!

I'm also guessing that you guys are first switching into an Orthographic projection before rendering the GUI...

I'm assuming so, as a GUI doesn't really "make sense" IMHO to be rendered under a perspective projection.

thanks again all, these are some real gems!

@Hiro: Thanks for the offer...I *might* take you up on it if I get stuck. But you're right. All of my work thus far has been behind creating a common codebase to use for the current (and future) projectwork. It's eaten up quite a bit of time, but I'm banking/hoping that it'll cut down all future work by ridiculous levels...:)

@Scott: Great idea about the macro for the callback system. I'll keep that
one in mind. ;)

milo
11-22-2004, 11:16 AM
Automatically rescaling works fine if you are going to stretch your font chars when the screen resolution increases. This makes sense in an arcade game or FPS where there is very little text and the fonts tend to be big anyways.

Many of the screens in my game have quite a bit of text on them, and the text is pretty small (e.g. http://www.starshatter.com/shots/s15.jpg). I prefer to keep the font pixels one-to-one with the screen pixels, and just increase the amount of data that I can present to the end user when the screen gets bigger. When I scale up a screen, I don't want to just multiply all the coordinates by a common factor. I want the controls to get bigger, but stay the same constant distance apart from one another, as they do in a web browser, for example. A constraint-based grid like the GridBagLayoutManager in Java Swing is ideal for this. As a bonus, it transparently handles wide-screen and resizable windows.

@luggage -

Yeah, I figured you were doing something like that. In retrospect, it's probably easier to do it your way than the thunk system I'm using. Oh well, maybe next time. Thanks. :-)

--milo
http://www.starshatter.com

keethrus
11-23-2004, 11:13 AM
Hey there,
My rule of thumb is that almost half of the time writing your first game should be spend towards common code, to be used in future games. UI controls should represent a fairly large percentage of that work.

-Hiro_Antagonist


I would have to completely agree here. I've just started out my company, GearFace.com (http://GearFace.com), and I don't plan on releasing my first game until late 2006.

Right now I'm just building things that I will need for every single product I will develop, with a GUI library framework being one of them.

That way, whenever I start a project, I grab my GUI that can handle any type of graphics (just change each widget's "drawMyself" function), grab my RSA library for doing licenses (encrypt and sign them, impossible to make a keygen function), grab my "no name yet" library to store/retrieve data in a single file easily, etc etc etc. With most of that out of the way, I can really focus on the more important things. :)

Of course it takes patience. I'm going to stay motivated by selling all my libraries as developer tools on my site. Earn some money in the meantime, and lets me set some milestones so I feel I am accomplishing something.

Ramble Ramble ... I'll stop now. :)

- Jeremiah

jaggu
11-24-2004, 01:54 PM
Dont get too caught up with a GUI library that has all the bells and whistles. Get something simple working and revise as necessary. Software never gets done anyway.

So, if your game needs buttons, do buttons (better still, see if somebody else has done buttons). No need for treeview, combo box etc even if you figure you will need it in future. You wont. And if you do need it, you can build it then. Why waste time? You can go out cycling or walk in the park knowing what a cool guy you are for not doing something you dont need right now ;)

EpicBoy
11-24-2004, 01:59 PM
That's really great advice when it comes to GUI code. I used to get all caught up in trying to handle everything imaginable when it came to UI controls. The only way I was able to actually get games done was to change my mindset to "just do what you need". No more, no less. Thinking about what you "might" need down the road just gets you deeper into time delays and your game not getting finished. Keep your eye on the prize.

stan
11-24-2004, 06:10 PM
For Smart Lines I created a simple menu system, where "buttons" are actually lines of text.

Menu_New() to create an empty menu, then Menu_AddEntry() to add each option (Menu_AddEntry() relayouts the menu each time it's called), and the classic Menu_Update() which checks for input and animates the background, and Menu_Draw().

Then I added the ability to draw a picture instead of a line of text (just one new MENUENTRY_PICTURE parameter to Menu_AddEntry() which is a vararg function - bad for type safety, but good for extensibility! (I'm coding in C)).

Then I added stuff to be able to include the volume gauges in the game menu with the same method.

The code is a bit of a hack at places, some stuff is hardcoded (for example the mouseover color is always white), but it does the job, and that's what matters :). And if I want to "de-hardcode" stuff, I can quite easily.

Emmanuel
11-25-2004, 01:27 AM
I would have to completely agree here. I've just started out my company, GearFace.com (http://GearFace.com), and I don't plan on releasing my first game until late 2006.

Right now I'm just building things that I will need for every single product I will develop, with a GUI library framework being one of them.


I have been guilty of overdesigning before, so I can tell you this: you probably should design and implement the libraries that you really need for your first game to come out, and if possible use third-party free libraries. For instance, do you really need to build your own format for storing pieces of data in one file? I know it's not very hard to do, but a lot of formats already exist with free tools (.tar being one..) and implementing a reader for those in your game is very easy.

As for GUI libraries, if you're doing a 2D game, you can combine GDI elements and DirectX code (at least in windowed mode). You can let GDI handle all the mouse, keyboard, state, etc. processing for you, and then you draw the elements yourself, of course (WM_ITEMDRAW and WM_PAINT can do a lot of things.). The two major benefits are that 1) you save a lot of time not reinventing wheels that will not bring you more customers, and 2) your game will react in a predictable way to your players, which will build comfort and sympathy.

wazoo
11-25-2004, 02:29 AM
The only way I was able to actually get games done was to change my mindset to "just do what you need". No more, no less. Thinking about what you "might" need down the road just gets you deeper into time delays and your game not getting finished. Keep your eye on the prize.

Sage advice EpicBoy, sage advice.

That's more or less the approach I'm ending up going. Sure it'd be nice to design and implement a huge GUI system like Swing (for C++), but at the end of the day, the finished product comes FIRST.

Just one of those many design vs. benefit decisions I think...

keethrus
11-29-2004, 10:45 AM
I have been guilty of overdesigning before, so I can tell you this: you probably should design and implement the libraries that you really need for your first game to come out, and if possible use third-party free libraries. For instance, do you really need to build your own format for storing pieces of data in one file? I know it's not very hard to do, but a lot of formats already exist with free tools (.tar being one..) and implementing a reader for those in your game is very easy.

I understand where you are coming from. However, I have the benefit of time on my hands. Since I need to find a full-time job, and I will be getting married soon, I'll be spending all my free time with my wife instead of working on anything seriously. So for the next year I plan on just developing these three libraries (RSA library, GUI framework, and library to organize and store data compressed in a single file).

Then, once 2006 comes along and I plan on devoting more time to my company, I'll have a strong foundation to really jumpstart any project I start. Plus I also plan on selling my libraries to other developers. ;)

Of course, if I was currently needing to create projects to sell to keep food on the table, I wouldn't have the luxury to just spend time making libraries. :)

- Jeremiah