The last week I have been working hard to add all the missing UI elements and widgets that were previously missing in H.A.A.R.P. Before I was testing everything with just buttons and check boxes but I couldn't really go on without testing on more types of elements to ensure everything was working in the right way. Therefore, over the past few days, in my time after work, I've been madly re-coding the UI elements that I have previously made to be compatible with Data Driven Design and more specifically H.A.A.R.P itself.
I have added the following Elements now:
- Check Boxes
- Text Boxes
- Drop Down Boxes
Although the above list is not a comprehensive list of all the elements you could ever think of or possibly need, I think that it is plenty for the first build of H.A.A.R.P GUI. I may have to add game specific elements or H.U.D elements later such as HP Bars etc. but I will leave that for another time.
Below is a screenshot with all the elements randomly placed over the screen. Please excuse the graphics I used for most of them it is simply just for testing. You can put any graphics you want for these elements, you simply have to save the .dds files in a game folder and the click on the green folders on a selected element to change the images used.
here is a picture of the Drop Down Box Selected. As you can see there are 8 little green folders because the Drop Box uses 8 little textures to put itself together. It could be less, however, the size and dimensions of the Drop Down Box become more restrictive.
These little green folders automatically detect how many textures a UI element uses and displays the relevant number of folders.
There are a lot of elements in any Gui to begin with but there are also many different sub types of elements. For example, a slider element can be either horizontal or vertical. In Designing the H.A.A.R.P elements I have taken this into consideration and enabled setting of element sub types. The type ID is stored in the database and can be changed in the editor. The behavior of an element depends on the typeID specified and if I need to create more behaviors for a single type of element i simply have to code the new behavior with reference to a new typeID.
Another example of this is Buttons. You can have a button that is simply an image, However, perhaps you want to only use one image for all your buttons and just write text over the top of that to make the Buttons different. Well, you can do that with H.A.A.R.P. Simply changing the Button type from 1 to 2 in the editor will do this.
Font & Element Labels:
Labels as an element is one thing, but what if you want a label for other elements so that they can be identified. For example, a slider might need a label that says "Master Volume". I could simply make another Label element, but that would just be much too much work and take up more memory than is necessary. Instead I have given every single element the ability to show its own label at a specified offset from the start Position of that element. The font style and color of the label can also be edited in the editor simply by changing a few number.
Below is an image of a button element drawing its own label. As this button is actually part of the editor I had to manually write the label name, color and offsets into the database. You may notice I didn't set a font for this one.
It should be noted that all this is taken out of the database including, 'whether to show or not to show a label', the label font, the label color (RGB), the label offset from the element. Everything comes from the database and nothing is hard coded. This allows for the ultimate control and ultimate re usability of the code.
Saving & Deleting:
I have recently implemented Saving of the UI elements new information back into the database. This task wasn't particularly hard as it just involved parsing the information from an element into an SQL statement string and then querying the database. However, Deleting elements was another story. Although it may sounds simple, I battled with deleting elements for 3 days in mega frustration.
It may sound easy but my database is set up is to make the least amount of columns possible. Therefore, there is a Generic_Element table which holds all data that is generic among all elements. This table kinda represents all the values stored in the element base class which is inherited to make a derived element specific class. On top of this table, I also have a table for each type of element and it holds all the element specific data. In order to make this work the tables need to reference each other. Each element has a generic ID and an element specific ID so deleting becomes difficult when you have multiple tables and you have to cross reference everything correctly, not to mention it having to be in-sync with the run-time information as well.
Now deleting wasn't even the hardest part, in fact it was as simple as parsing the generic ID and the element specific ID of an element into an SQL statement string and querying the database. However, once this has been completed all element above the deleted element have to have their ID's rotated downwards. This was really difficult more as a logistical thing than a coding thing. It took me a long time and much frustration to figure it out. However, I have won and the deleting algorithm is down pat now.
Below you should be able to see what I mean about the databases.
Although this setup causes problems in deleting. It is more beneficial than it is detrimental.
Separating The Editor From the Game:
When I started making and designing HAARP I decided it was very important that this "In game editor" did not interfere with the performance of the game when it is actually being played in any way. Therefore, I constructed the HAARP editor completely separate from the game code and simply given editor access to the game objects via pointers. Once the editor is turned off there is literally no effect on the game whatsoever except for a single 'if' statement. Also once a game is completed, I simply have to comment out a single #define line and it is as if the HAARP editor never existed.
I am happy that I made this decision early on in the piece because the complexity of the editor is much greater than that of the actual screen state code. All the Screen state code really does is cycle through all the elements and updates them. The elements are designed in a way that they fully manage themselves and their own relationships with other variables, functions and screens.
This blog turned out way longer than I had anticipated. Oh well. I hope you enjoyed it and maybe learned something.