« Back to tutorial listing

— Mission-based 2D shoot 'em up —
Part 14: Start of intermission

Note: this tutorial assumes knowledge of C, as well as prior tutorials.

Introduction

Now that our core gameplay is mostly established, its time to move on to the intermission section. This is where the player can select missions, upgrade the KIT-E, see stats, and all the rest. There are a number of section in the intermission, some more complex than others. We'll be working through them one at a time. To begin with, we're going to layout how our main intermission screen will operate, and then bolt the other pieces on in subsequent parts.

Extract the archive, run cmake CMakeLists.txt, followed by make, and then use ./shooter3-14 to run the code. You will see a window open like the one above. Use the mouse to control the cursor. The icons at the bottom of the screen can be interacted with by clicking on them. Other than changing colour, they don't do anything else. Once you're finished, close the window to exit.

Inspecting the code

Our intermission will be presented in the form of screen with a series of icons at the bottom, that can be clicked on to change section. Let's get started on the ground work before we go about implementing the different sections.

First, we've updated defs.h:


enum
{
	IS_PLANETS,
	IS_COMMS,
	IS_SHOP,
	IS_STATS,
	IS_LOAD_SAVE,
	IS_OPTIONS,
	IS_MAX
};

We've added an enum group to represent our different section. IS is short for Intermission Section. We'll see these enum values used throughout the intermission.

Turning now to our new compilation unit, intermission.c. This file already contains a number of functions for us to work through. The first is initIntermission:


void initIntermission(void)
{
	int i, x;

	initStarfield();

	background = loadTexture("gfx/backgrounds/default.jpg");

	sectionIconTexture = getAtlasImage("gfx/intermission/sectionIcon.png", 1);
	sectionIconHoverTexture = getAtlasImage("gfx/intermission/sectionIconHover.png", 1);
	sectionIconSelectedTexture = getAtlasImage("gfx/intermission/sectionIconSelected.png", 1);

	sectionIconTextures[IS_PLANETS] = getAtlasImage("gfx/intermission/planetsIcon.png", 1);
	sectionIconTextures[IS_COMMS] = getAtlasImage("gfx/intermission/commsIcon.png", 1);
	sectionIconTextures[IS_SHOP] = getAtlasImage("gfx/intermission/shopIcon.png", 1);
	sectionIconTextures[IS_STATS] = getAtlasImage("gfx/intermission/statsIcon.png", 1);
	sectionIconTextures[IS_LOAD_SAVE] = getAtlasImage("gfx/intermission/saveIcon.png", 1);
	sectionIconTextures[IS_OPTIONS] = getAtlasImage("gfx/intermission/optionsIcon.png", 1);

	x = sectionIconTexture->rect.w * IS_MAX;
	x += 48 * (IS_MAX - 1);
	x = (SCREEN_WIDTH / 2) - (x / 2);

	for (i = 0; i < IS_MAX; i++)
	{
		sectionIcons[i].x = x;
		sectionIcons[i].y = SCREEN_HEIGHT - 125;

		x += sectionIconTexture->rect.w + 48;
	}

	section = IS_PLANETS;

	starfieldTimer = 0;

	app.delegate.logic = logic;
	app.delegate.draw = draw;
	app.mouse.showCursor = 1;
}

Like initStage, this is the main entry point into our intermission. All the main logic and rendering will be handled here. We start by setting up our starfield and loading a background. You will have notice that, like the main game, we're drawing a space scene and stars. Next, we're loading a series of icons. sectionIconTexture is the default background of our icon, sectionIconHoverTexture the texture used when the mouse hovers over an icon, and sectionIconSelectedTexture is the texture used when we have an icon selected. Next, we're loading the actual icons into an array called sectionIconTextures, of IS_MAX in length.

With that done, we're doing some calculation to align our icons along the bottom of the screen. sectionIcons is an array of SDL_Points, once again of IS_MAX length. With that done, we're setting a variable called `section` to IS_PLANETS. The `section` variable will control which section we're currently in. starfieldTimer is then set to 0. Our starfield changes direction every so often, and this variable is used to control the frequency of that chance. Lastly, we're setting our `logic` and `draw` delegates, and also setting App's mouse's showCursor flag to 1, so that our mouse pointer is displayed.

Now for our `logic` function:


static void logic(void)
{
	starfieldTimer -= app.deltaTime;

	if (starfieldTimer <= 0)
	{
		ssx = rand() % 10 - rand() % 10;
		ssy = rand() % 10 - rand() % 10;

		ssx *= 0.05;
		ssy *= 0.05;

		starfieldTimer = (FPS * 5) + (rand() % (FPS * 5));
	}

	doBackground(ssx * app.deltaTime, ssy * app.deltaTime);

	doStarfield(ssx, ssy);

	doSectionIcons();
}

The first thing we're doing is reducing starfieldTimer, and then checking if it's 0 or less. If so, we're going to randomly assign `ssx` and `ssy` new values. `ssx` and `ssy` are static variables in intermission.c, and, like with those variables found in the Stage struct, they are used to control the speed of the stars and background movement. We then set starfieldTimer to a random value between 5 and 9 seconds, which will determine when the starfield movement randomly changes once more. We're then calling doBackground and doStarfield, to scroll them (as in stage.c). Lastly we're calling a function named doSectionIcons.

Not a lot going on just yet, but this will change in future parts. Now, onto doSectionIcons:


static void doSectionIcons(void)
{
	int i;

	hoverSectionIcon = -1;

	for (i = 0; i < IS_MAX; i++)
	{
		if (collision(app.mouse.x, app.mouse.y, 1, 1, sectionIcons[i].x, sectionIcons[i].y, sectionIconTexture->rect.w, sectionIconTexture->rect.h))
		{
			hoverSectionIcon = i;

			if (app.mouse.buttons[SDL_BUTTON_LEFT])
			{
				app.mouse.buttons[SDL_BUTTON_LEFT] = 0;

				if (i != section)
				{
					section = i;
				}
			}
		}
	}
}

This function is responsible for driving the interactions with the sectionIcons. We basically loop through all our sectionIcons, testing if the mouse cursor is over one. If so, we're setting a variable called hoverSectionIcon (static in intermission.c) to the value of `i` (in other words, which icon is currently being hovered over). Next, we're checking if the left mouse button has been pressed, and if we're not already viewing this section, we're setting `section` to `i`. So, in summary, we're checking for clicking on icons, and providing visual feedback for the mouse hovering over icons.

That's our logic done, so we can now look at the rendering. Our `draw` function comes next:


static void draw(void)
{
	drawBackground(background);

	drawStarfield();

	drawSectionIcons();
}

Not much to say here. We're drawing our background and starfield, and also calling a function named drawSectionIcons. Let's look at that now:


static void drawSectionIcons(void)
{
	int         i;
	AtlasImage *texture;

	for (i = 0; i < IS_MAX; i++)
	{
		texture = sectionIconTexture;

		if (i == section)
		{
			texture = sectionIconSelectedTexture;
		}
		else if (i == hoverSectionIcon)
		{
			texture = sectionIconHoverTexture;
		}

		blitAtlasImage(texture, sectionIcons[i].x, sectionIcons[i].y, 0, SDL_FLIP_NONE);

		blitAtlasImage(sectionIconTextures[i], sectionIcons[i].x + 7, sectionIcons[i].y + 7, 0, SDL_FLIP_NONE);
	}
}

This function does as the name suggests - it draws the section icons. We setup a for-loop to go from 0 to IS_MAX. We set `texture` as sectionIconTexture, to act as the default background texture, then test if `i` is equal to `section` (the currently active section) or `i` equal to hoverSectionIcon (the icon the mouse is resting over), and update it appropriately. We then draw the chosen texture, before overlaying the appropriate icon. Using this composite technique means we only need three total background images, rather than three different images for each of our icons..!

That was easy! There's not a lot to see and do right now, but we've now finished the ground work for our intermission section, so it's now just a case of implementing all the individual pieces. In the next part, we'll start with the system star and planets view.

Purchase

The source code for all parts of this tutorial (including assets) is available for purchase:

From itch.io

It is also available as part of the SDL2 tutorial bundle:

Desktop site