Programming UI for Critters
I never really thought about how UI is coded for games. For me, mostly working with OS level APIs UI was something that's handled by the OS and I just mostly put my controls on the provided IDE's canvas and code away - mostly.
Even for fun, when making mechanical prototypes at home, UI was almost an afterthought. The most I ever made was maybe a start screen with a few buttons to start game or quit game. It worked fine for my needs and even when I started seriously working on ABC-Pop, UI was the last thing I started to work on. Pretty much all the mechanics for the game was finished at that time.
I mean, how hard can it be? Put buttons on the window, and when clicked, change something.
Well, as it turns out it can be pretty fucking hard. I soon found myself entangled in 3 separate execution loops all firing different type events toward the main loop all juggling in my head and me trying to keep it all under control. And if you've seen the trailer for ABC-Pop you can accurately observe that 80% of the game is just UI.
After a week of The Dark Times, I finally said enough and started to work on a proper UI library that I can use for all my future projects. The end product now is called AndUIn and you can see it in action in ABC-Pop.
So why didn't I just use some readily available UI libraries? Two reasons. 1st. The ones I looked at force me to use their own programming paradigm that would make me reprogram the basics of how my own 2D engine works, and second and the primary one is: I love trying to tackle programming problems for my self. And making my own UI library is just the kind of things I love doing.
Enter AndUIn - Android User Interface.
I first started with the base class that any control would inherit from - Widget. It contains most of the inherited properties of the control, such as Position, bounding rectangle, focus, and some primitive drawing functions in SDL drawing the control if no texture is set and a HandleEvent overrides.
Expanding on this, I made buttons, labels, checkboxes and some other standard UI controls.
Next I made Window controls. These are separate controls that don't inherit from widget but do contain the list of widgets to display in its Draw() function.
Next big thing of course was firing and handling events. Windows handle events passed to them from the engine which are then passes to their respective controls. And here we come to the big one. If engine has processed a MOUSE_DOWN event from the main loop, passed it to UI. and the game_state is GAME_STATE_UI and a Window in focus has processed the event, found that click has happened in the bounding box of the button, how do we process that click?
We can't just process clicks from the button and hard code each button's event. It defeats the purpose of Window/Control based pattern design. (I think).
In other words, If we have a MainWindow inheriting from a window, make a button, add it to the Window control list, we must have a way to make the button's OnClick function, somehow bind to the parent window's OnClick_Reset() - for example.
And this brings us to the heart of the UI design. Biding functions from a Window, to OnClick function of the Button.
So if we want to to that, the first thing we dois dust of our pointers to functions knowledge. Not that because I'm not that stupid. The first thing we do is finally go to the internet and find something to do that for us. And luckily, someone way more smarter than me already did that.
Enter FastDelegates Library. Incredible and easy to use API that enables us to cast pointers to functions relative to the parents class.
And viola. All pieces of our UI for games are now complete and ready to use.
Here we Initialize the AndUIn window, Add a button and bind it to GameOverWindow's OnClick_Reset() function.
And here is the UpgradeWindow inheriting from TabWindow in action. Please note that all visuals and text are mostly a placeholder for the future work.
If you're interested in Critters or find this blog moderately interesting,
You can follow me on Twitter for news and updates
https://twitter.com/CrittersDev
Even for fun, when making mechanical prototypes at home, UI was almost an afterthought. The most I ever made was maybe a start screen with a few buttons to start game or quit game. It worked fine for my needs and even when I started seriously working on ABC-Pop, UI was the last thing I started to work on. Pretty much all the mechanics for the game was finished at that time.
I mean, how hard can it be? Put buttons on the window, and when clicked, change something.
Well, as it turns out it can be pretty fucking hard. I soon found myself entangled in 3 separate execution loops all firing different type events toward the main loop all juggling in my head and me trying to keep it all under control. And if you've seen the trailer for ABC-Pop you can accurately observe that 80% of the game is just UI.
After a week of The Dark Times, I finally said enough and started to work on a proper UI library that I can use for all my future projects. The end product now is called AndUIn and you can see it in action in ABC-Pop.
So why didn't I just use some readily available UI libraries? Two reasons. 1st. The ones I looked at force me to use their own programming paradigm that would make me reprogram the basics of how my own 2D engine works, and second and the primary one is: I love trying to tackle programming problems for my self. And making my own UI library is just the kind of things I love doing.
Enter AndUIn - Android User Interface.
I first started with the base class that any control would inherit from - Widget. It contains most of the inherited properties of the control, such as Position, bounding rectangle, focus, and some primitive drawing functions in SDL drawing the control if no texture is set and a HandleEvent overrides.
Expanding on this, I made buttons, labels, checkboxes and some other standard UI controls.
Next I made Window controls. These are separate controls that don't inherit from widget but do contain the list of widgets to display in its Draw() function.
Next big thing of course was firing and handling events. Windows handle events passed to them from the engine which are then passes to their respective controls. And here we come to the big one. If engine has processed a MOUSE_DOWN event from the main loop, passed it to UI. and the game_state is GAME_STATE_UI and a Window in focus has processed the event, found that click has happened in the bounding box of the button, how do we process that click?
We can't just process clicks from the button and hard code each button's event. It defeats the purpose of Window/Control based pattern design. (I think).
In other words, If we have a MainWindow inheriting from a window, make a button, add it to the Window control list, we must have a way to make the button's OnClick function, somehow bind to the parent window's OnClick_Reset() - for example.
And this brings us to the heart of the UI design. Biding functions from a Window, to OnClick function of the Button.
So if we want to to that, the first thing we do
Enter FastDelegates Library. Incredible and easy to use API that enables us to cast pointers to functions relative to the parents class.
And viola. All pieces of our UI for games are now complete and ready to use.
Init Game Over Window |
Here we Initialize the AndUIn window, Add a button and bind it to GameOverWindow's OnClick_Reset() function.
And here is the UpgradeWindow inheriting from TabWindow in action. Please note that all visuals and text are mostly a placeholder for the future work.
Tab Window Control |
If you're interested in Critters or find this blog moderately interesting,
You can follow me on Twitter for news and updates
https://twitter.com/CrittersDev
Comments
Post a Comment