Spacecrash day 5 of 7: fonts and menus
So today I took the time to add some text-based menus. Nothing out of the ordinary, but something necessary for any complete game. I spiced up the menu just by having graphics from the game in the background – this is a common trick by all cost-conscious game developers since time immemorial!
First thing I needed some way to draw text. OpenGL doesn’t provide any built-in way to do so, so you need to do it your own way. The simplest thing is to prepare a texture with your font, and paint pieces of this texture for each character. You can see the texture right next to this text (this is a font by Marc Russell from SpicyPixel – thanks!), and here is the code to do the text drawing using this font:
As you can see, the PrepareFont() function explores the table mapping where the characters are, and prepares an alternate fontchardefs array which is easier to use for drawing later on.
Once we have this, we need to implement the drawing and input-handling of menus. To handle keypresses, the existing SYS_IsKeyPressed() functionality is not enough, because you don’t want to keep moving the selection while the key is pressed. So I have added logic to know when a key has just been pressed:
That way, code can check “g_just_pressed_up” and be safe knowing there won’t be unwanted “autorepeats”.
Next thing is defining the menus in a common format, and writing the code to render them and to handle input:
This takes over 300 lines of code, as you see, more than our Windows OpenGL support, or more than our core sound engine! This is often the case in games: things that are not really very exciting may end up taking more work than the high-tech ones!
Finally, we need to integrate this into the main game. It is not difficult, but you have to take into account all conditions. I’ve added two main new GameState types (GS_MAIN_MENU and GS_INGAME_MENU). When in a menu, ProcessInputMenu() has to be called instead of the regular ProcessInput(), RenderMenu() has to be called, and I’ve had to implement a few extra functions such as FinishGame(). Here are the highlights of this integration code:
The code is a bit messy in places now, with handling belonging to things in wholly separate conceptual areas too intermixed (for example, running the menu and running the rocket-shooting are in completely different levels, and the code should reflect that). I’ve done so for the ProcessInput() code, but I should find some time do that for the running, rendering, etc…
Here you can get the whole latest version of the code and graphics: sc-day-5.zip.
And here is how this looks now:
So at the end of day five, we have all the core elements for a complete game. Tomorrow I will work in preparing an installer, which is the last critical piece. But there are several key areas that still need work:
- Gameplay and difficulty progression
- Sound and music
- Graphics effects
And there are a few glitches to fix up: sound has to be paused in the in-game menu, progression data has to be saved to disk, and probably a few more like this.
I will work on these things on Sunday and finish a “1.0” version, and most likely, I will invest a couple more days next week for the final polish. I think even this reflects pretty well on how a game development project usually works!
And if you want to be notified when new articles to help you become a games developer are ready, just fill in the form below: