This is another post in the Lessons Learned series. Today’s lesson: immediate-mode GUIs
I’ve you have ever worked with Win32, GTK, or pretty much any GUI toolkit I know of, you’re probably used to treating the GUI as a bunch of controls. If you need a button on the screen then you create an instance of the Button class and add a pointer to that button to the Window object. Then behind the scenes Windows or GTK or whatever handles the rendering and processing of the button. All you have to do is wait for the user to click it.
So when creating a GUI for a game, it’s natural to take the same approach. You think, “oh, I need a button here, so let me create a Button class, and it’ll inherit from the Control class, which itself inherits from the GUIObject class.” You know, all the stuff they taught you to do in that object-oriented programming class back in college.
But is that necessarily the best way to do it? Imagine the simplest case: a label. The OOP way to do it would be to create a Label class, then create a new instance of Label and add it to your control hierarchy. And the Label needs to store its position, and text, and color, and anything else we need it to do. If we need it to do anything dynamic then we’ll update it from the parent control.
But why? Why do it that way? Why not just call RenderText() from the parent control’s render code? It’s a lot simpler, most likely requires less memory, and is just as powerful. We’re not writing desktop apps; we’re writing games with a game loop that executes every frame. Let’s take advantage of that.
The CnK GUI started out extremely OOP-based. It would have made my old college professor proud. Now it’s still a bit OOP (menus and buttons are still objects), but over time it has become less and less OOP, and the less OOP it becomes the more I like it.
I didn’t come up with this whole immediate-mode idea. Here’s a good explanation that goes into way more details.
Moral: Don’t assume what they taught you in school is the best way to do something.