Immediate GUIs in XNA, Setup and a button
Part 2 (Scrollbars) is located here
Immediate GUI’s are a pretty new concept to creating and drawing GUIs. One of the big differences between an Immediate (IM) GUI and a normal GUI is that an IMGUI is non persistent. Every frame a manager determines which screens/buttons/widgets have to be drawn and only these are drawn. There are no Button objects, Form objects or objects at all. GUI items are immediately drawn by calling a method. Most of these methods are prefixed by ‘Do’ to show the immediate nature of the button. Because of this, IMGUIs have a very low memory profile. However some objects are created every frame for drawing purposes and these might go havoc with the garbage collector if you don’t watch them properly (especially on the Xbox).
Because no objects are used, we have to use a special trick to keep track of ‘events’. To accompany this, every GUI item that can have a certain state, or can return something (for example a button, for which we want to know if it was clicked) is given a unique id (usually an integer). The IMGUI manager holds a couple of variables to determine what item was clicked, what item the mouse was over and what item is receiving keyboard input. So the state literally consists of 3 integers, instead of a great series of objects.
Let’s create a framework for our own IMGUI in XNA.
Fire up a new XNA Windows Game project and create a new class called IMGUI. Add the following using statements:
After that add the following fields:
We need a SpriteBatch to draw our GUI. The hotItem will store the ID of the item where the mouse is over. The activeItem will store the item being clicked. We will also store the mouse state so we don’t have to get the mouse state in every GUI item.
Let’s add an update method to automatically update our mouse.
Nothing fancy here, but this will keep track of the mouse.
We want our IMGUI to be selfcontained but we still need to begin and end our spriteBatch. We also need to clear the hotItem (the item where the mouse is over) before beginning. And at the end we need to check if the mouse is still pressed, if not we need to store in activeItem that no item is being clicked. To accommodate this, we will make a Begin() and End() methods, not unlike those of the normal spriteBatch.
It might still seem a bit odd why we have to do this. But when we create our first GUI item, it will make a lot more sense. So let’s get right on it!
As you can see this is not much code for a button, because we got rid of all the state information and just bother ourselves with drawing a button, we don’t need to do much at all. Let’s look at what we have here. First we determine if the mouse is over our button. If that is the case we are ‘hot’. We set the hotItem to our id, we also check if no item is active, and if the mouse’s left button is pressed. If so we set ourselves to be the activeItem as well.
We then start to draw our button (nothing fancy, we just change the tint we apply to our texture, and then draw the texture at the specified place).
At the end of our method we check if the mouse was released. If the mouse released and we where the hot and active item (the mouse is over our button and the mouse was pressed when over our button) then we return true to signal that we where clicked, else we return false. Because we store those nifty hot and active item integers this is all we need to determine if we were pressed.
Using the button and the IMGUI would look something like this:
Easy isnt it? Just make sure that you keep your ids unique, and that you give the same button the same id every frame. Of course after a button is no longer used, you can reuse the id (make sure though that you wait at least one frame, or to check that the hotItem and activeItem where not set to the id you are going to reuses, else some false clicks might occur, but generally this shouldn’t be a problem).
If there is more animo I’ll write a following part somewhere next week. Here we are going tot tackle scrollbars and textfields, which are slightly more interesting because they require their own output to be inputted next frame.
Oh btw, one of the biggest sources on immediate GUIs is the website mollyrocket.com IMGUI video I’ve directly linked the one hour long video. Skip the first few minutes about “why this is a video tutorial, because he doesn’t have much time etc..” and delve straight into the interesting part!
Update 30-03-2010 added a call to imgui.Update(..) which I forgot and only saw in the next installment in this series.