Skip to main content

Set The Controls For The Heart Of The Sun

When we last met, I had just started work on a level editor. I'd got as far as adding the ability to select an object and move it around, and then I added an undo/redo system using the command pattern. That was a good start, but dragging items around the level is only fun for so long. What I really want to be doing is..


..editing the properties of the bullet spawners! And I want to be doing this in realtime as the game plays so that I can immediately see what effect my changes have made to the gameplay of the level.

The GUI

First things thing - I'm not going to dive too deeply into my GUI code. There are a few reasons for this. Firstly, it's not trivial - it could easily be a whole series of tutorials in itself. Secondly, it's still a work in progress - the code is a bit messy and it's changing all the time. I'm actually using the GUI code across two different projects, so it's changing quite quickly and not all of the changes are related to this project.

Having said all that, let's spend some time talking about the theory of the GUI. There are two main types of GUI, and these are commonly called either "retained mode" or "immediate mode" - both have their pros and cons.

In a retained GUI we create long-lived objects (windows, input controls, etc.) that are managed by the client code as well as the GUI system itself. Data values (aka state) are stored inside these objects and we must marshal the data backwards and forwards between the objects and the client code. The marshalling is usually done through events - the GUI manager raises an event when the user changes the data, and the client code sends events to the GUI manager when it changes the data. This all takes time (and code) but the benefit is that the GUI manager has a complete model of the system at all times. This allows it to make optimisation choices about how to manage the data, and particularly how to render it. For instance, if nothing changed in the GUI since last frame (eg: the user made no input) then maybe the system can get away without having to draw anything new at all. Retained mode GUIs are the more "classical" mode of GUI, implemented by systems like HTML, Microsoft Windows or Qt. Using this sort of GUI to make a property editor for a game obejct might look like this:


Immediate mode GUIs are quite different. Instead of creating long-lived objects that contain state, no objects are created at all and the state is only ever kept inside the client code. That's not to say that there isn't any GUI state (there is) but that state is relatively simple, and it's hidden away inside the GUI manager code itself. Immediate mode GUIs are much easier for client code to use:


See just how much less code the immediate mode GUI needs? And, as you can imagine, the retained mode GUI adds more code as we add more editable properties whereas the immediate mode GUI's client code remains pretty simple. But you can also see how the retained mode GUI does not need to do anything in an update() function, so when the state is not changing then very little extra code is being run - unlike the immediate mode GUI which has to pass the whole state to the GUI manager each frame.

I'm not totally convinced that immediate mode GUIs are a great solution, but I've only ever written and worked with retained mode GUIs before so I don't have that much experience of them. Sometimes it's a good idea to try something that you don't agree with, just to see how it works. This is especially true if you have the opportunity to try something in an actual real-life project, like I do here. To be fair, I'm enjoying developing and using an immediate mode GUI so far. It certainly makes development a lot faster (speed is high for both the GUI and the client code) and the performance is not suffering given that I have such simple requirements for my GUI.

If you want to find out more about immediate mode GUIs then the first resource to look at is probably Casey Mutraori's presentation, which can be found on YouTube. You should also check out the C++ implementation Dear ImGui.

Editing Object Properties

When an object is clicked on, an editor window pops up displaying all of the editable properties for that object. How does this get created? Would I have to write a different editor for each different object type? No - I can leverage the object schema code that I wrote and talked about a few posts ago. The schema for an object gives me a name, type and the range of valid values for each possible property type. It's pretty trivial to look through this list and generate an editor that is specific to the selected object. The code looks something like this:


The harder part is to figure out when the user has edited the values in the GUI - remember that this is an immediate mode GUI and I don't get any callbacks or notifications that changes have been made. So what do I do? Simple. Each frame I take a copy of the original config data and pass that to the GUI editing controls. Changes are made directly to that copy of the data. I then compare the original data against the copy and if they differ then I know that the user made changes. When this happens I can parcel the changes up into a new "change object configuration" command type - remember that all changes to an object go through the command pattern so that undo/redo can be implemented. It's not the most efficient thing to do, but at this scale I think the simplicity of the code wins out - the extra performance hit of doing this every frame is never going to be noticeable.

The whole code for editing object properties looks like this:

Wrapping Up

In this post I added an immediate mode GUI to the game and then I created a pop-up window for editing object properties. The list of properties in this editor window are automatically generated from the list of properties that I defined for each object as part of their schemas.

As always, the code is available here and the editor can be played online here. Use the mouse to edit, CTRL+Z and CTRL+Y to undo and redo your edits and SPACE to start/stop the game running. You can also hide/show the GUI by pressing the ` key.

Next Time

Editing levels is fun, so let's do more of that! Next time I'll add some more editing facilities like the ability to create new objects. I'll also look at easy ways to import and export your levels because, you know, sharing is caring. These changes will make the editor into a fully functioning one.

Comments

Popular posts from this blog

World In Motion

In the last post I touched on how easy it is to score in this game - you can just camp out on the score bullet spawner and watch the points rack up. I'm going to add a little delay to the score bullets so that they start out in a deactivated and uncollectable state, and then change to active and collectable after a short time - say, half a second. To make it clear what state they are in I'm going to add code to let me change the look of Objects and allow them to be animated.

The Long And Winding Road

I started this blog back in November of last year. My aim was to document the development of a Bullet Hell shoot-em-up, written in JavaScript. Here we are, six months later, and lots has happened. With 20 posts already written, I thought that now would be a good time to take stock of what I've already done, and to look to the future and see what's to come.