Simple Game Scenes

In this example we'll set up a simple structure for a game to pass from, for example, a title screen to the game itself. This can also be called game states.

Separating these scenes means that they can have their own separated and independent logic, loading different graphics and handling inputs differently.

Let's assume you have two scenes for now, so at the top of your main.c file we can add:

enum GAME_SCENE
{
    SCENE_TITLE,
    SCENE_GAME
};

Under this add a variable to track the active scene:

enum GAME_SCENE currentScene;

Now let's add a function to initialise the default scene:

void Init()
{
    currentScene = SCENE_TITLE;
}

Here we set the default scene to be SCENE_TITLE, you can change this to start at any other for debugging.

Let's add a couple of functions for each of the scenes we added before:

void runSceneTitle()
{
//TODO: add Title code
}

void runSceneGame()
{
//TODO: add Game code
}

Now we need our main() function to tie all this together.

This works by calling the basicInit() function to set the default Scene, then loop using a switch statement to call the appropriate scene function.

void main()
{
    Init();
    while(1)
    {
        switch(currentScene)
        {
            case SCENE_TITLE:
            {
                runSceneTitle();
                break;
            }
            case SCENE_GAME:
            {
                runSceneGame();
                break;
            }
        }
    }
    return (0);
}

With the scaffolding done, let's add to the separate scene functions so we can see something happen.

Edit the scene functions to look like this:

void runSceneTitle()
{
	put_string("TITLE SCREEN", 1, 1);
}

void runSceneGame()
{
	set_font_color(0, 1);
	load_default_font();
	put_string("GAME SCREEN", 1, 1);
}

Both functions now use put_string to write text to the screen. We'll change the font and background colour with set_font_color to make it easier to see the difference between the two scenes.

If we compile and run what we have, this is what we should see:

We don't yet have a way to move to the next scene so before main let's add a means of doing that now:

void joyHandlerTitle()
{
    unsigned int j1;
    j1 = joy(0);
    if (j1 & JOY_RUN) {
        currentScene = SCENE_GAME;
    }
}

This simple function detects if the Run button is pressed and changes the currentScene .

It's good practice to have a separate input handler for each scene, so that each can have separate logic.

Let's amend the runSceneTitle function a little to use the joyHandlerTitle function we added.

void runSceneTitle()
{
    while(currentScene == SCENE_TITLE){
	put_string("TITLE SCREEN", 1, 1);
	joyHandlerTitle();
    }
    cls();
}

We've also added a while condition here so that there is a running loop in this function while the current scene is SCENE_TITLE so that the screen can be cleared before moving to the next scene.

If we compile and run again, and press the Run button you should see the next scene:

And that's it—we now have a working scaffolding for scenes in our game.

Here is the complete code for this example.

#include "huc.h"

enum GAME_SCENE
{
    SCENE_TITLE,
    SCENE_GAME
};

enum GAME_SCENE currentScene;

void Init()
{
    currentScene = SCENE_TITLE;
}

void runSceneTitle()
{
    while(currentScene == SCENE_TITLE){
		put_string("TITLE SCREEN", 1, 1);
		joyHandlerTitle();
    }
    cls();
}

void runSceneGame()
{
	set_font_color(0, 1);
	load_default_font();
	put_string("GAME SCREEN", 1, 1);
}

void joyHandlerTitle()
{
    unsigned int j1;
    j1 = joy(0);
    if (j1 & JOY_RUN) {
        currentScene = SCENE_GAME;
    }
}

void main()
{
    Init();
    while(1)
    {
        switch(currentScene)
        {
            case SCENE_TITLE:
            {
                runSceneTitle();
                break;
            }
            case SCENE_GAME:
            {
                runSceneGame();
                break;
            }
        }
    }
    return (0);
}

Last updated