Wednesday 23 January 2008

GUI musings

Today I decided to flesh out my engines GUI system. I've decided to write all of the functionality pretty much from scratch. Partly to learn about game GUIs and partly to ensure that I can modify it without having to worry about how it affects others or any licensing issues.

Design wise I've decided to go with a GUIManager class. It handles the input listening, enabling/disabling and general drawing functionality. I want the gui system to be flexible enough to use for any 2D display, from basic information and control windows, to hud elements. This means that it has to know when to and when not to intercept the game controls. I can do this with a simply toggle switch, which will stop the listen function from being called. Crucially the control will still be drawn and the game can still manually update the values in the control (think health bars, energy readouts etc. etc.).

The first control I created is a simply bitmap background. This get's drawn before anything else and all other controls appear on top of it. I am also considering having this control able to contain the game output. Due to post processing, the game is effectively rendered to a readily available full screen texture anyway. Of course you can specify which region the bitmap takes up, so it's already possible to render two different player views and add then split screen to the display :)

This was the simplest control to write as it just blaps a texture to the screen using the rectangle specified. It doesn't care at all what the image is.

The next control I tackled was a bitmap button. This control allows me to use my art assets as buttons. I can assign images for idle, highlighted and pressed. In practice, you don't see the pressed image for more than a few milliseconds as this is usually what triggers a state/screen transition. To go along with this I implemented a simply button group system. This is based on the code provided in the microsoft tutorials but, with some heavy modification. The button group contains a list of buttons that have been assigned to it. It will draw all of these buttons but, only passes user input messages to the active button. User movement messages are used to step backwards and forwards through the list of buttons. Crucially a button group can contain other button groups and (provided you remember to map the controls correctly) stepping between them is hastle free. I currently have the top level group use the bumpers to step through the groups and the groups use the up/down on analogue or d-pad to move through their controls.

Finally today I created a toggle button. This turned out to be harder than I thought. Not because it was difficult to code mind you. It was made harder, due to my own short sightedness, when I created the button group class. I had hard coded the button group to only understand what GUIBitmapButtons were! I ended up having to go through the entire class and change each reference to a generic GUIWidget. I then had to expand the next and previous functions to cast the button to the correct type before using it. I thought about making the GUIWidget class encapsulate more of the basic functionality so that I didn't need to cast anything. This would ruin my interface system though, as I currently use a list of interface types to store all of the currently active widgets.

I may post a more complete description of my gui system for anyone who want's to role their own. I find that it's the best way to understand what's going on and to learn new things. You never know what you will come up with when you try to create a feature or function you haven't tackled before.

No comments: