PC Games

Orb
Lasagne Monsters
Three Guys Apocalypse
Water Closet
Blob Wars : Attrition
The Legend of Edgar
TBFTSS: The Pandoran War
Three Guys
Blob Wars : Blob and Conquer
Blob Wars : Metal Blob Solid
Project: Starfighter
TANX Squadron

Android Games

DDDDD
Number Blocks
Match 3 Warriors

Tutorials

2D shoot 'em up
2D top-down shooter
2D platform game
Sprite atlas tutorial
Working with TTF fonts
2D adventure game
Widget tutorial
2D shoot 'em up sequel
2D run and gun
Roguelike
Medals (Achievements)
2D turn-based strategy game
2D isometric game
2D map editor
2D mission-based shoot 'em up
2D Santa game
SDL 1 tutorials (outdated)

Latest Updates

The Legend of Edgar 1.37
Mon, 1st January 2024

SDL2 Santa game tutorial 🎅
Thu, 23rd November 2023

SDL2 Shooter 3 tutorial
Wed, 15th February 2023

The Legend of Edgar 1.36
Sun, 1st January 2023

SDL2 map editor tutorial [UPDATED]
Sat, 10th September 2022

All Updates »

Tags

android (3)
battle-for-the-solar-system (10)
blob-wars (10)
brexit (1)
code (6)
edgar (9)
games (41)
lasagne-monsters (1)
making-of (5)
match3 (1)
numberblocksonline (1)
orb (2)
site (1)
tanx (4)
three-guys (3)
three-guys-apocalypse (3)
tutorials (15)
water-closet (4)

Books


A North-South Divide

For over a hundred years, messenger Duncan has wandered the world, searching for the missing pieces of an amulet that will rid him of his curse; a curse that has burdened him with an extreme intolerance of the cold, an unnaturally long life, and the despair of watching all he knew and loved become lost to the ravages of time. But now, Duncan is close to the end of his long quest.

Click here to learn more and read an extract!

« Back to tutorial listing

— 2D Santa game —
Part 5: Gifts and coal

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

Introduction

This wouldn't be Christmas Eve without Santa hurling a load of gifts down chimneys (or coal, if you're on the Naughty List). In this part, we're going to implement code to allow the player to deploy such items from his sleigh, raining them down onto the dwellings below.

Extract the archive, run cmake CMakeLists.txt, followed by make, and then use ./santa05 to run the code. You will see a window open like the one above, with the scene moving from right to left. Steer Santa's sleigh with the WASD control scheme, and use J and L to throw a gift or a lump of coal. At the moment, these two items are unlimited. The objects will be removed from the game when they hit the ground and cannot, as yet, enter chimneys. When you're finished, close the window to exit.

Inspecting the code

Adding in our gifts and coal is yet again an easy task; they are just entities that have `tick` and `draw` functions. We need only spawn the entity, assign all the relevant details, and have our game loop take things from there. Once again, you can see that this is straightforward to do, so let's hop to it.

Starting with defs.h:


enum
{
	// snipped
	ET_GIFT,
	ET_COAL
};

We've added two new enums - ET_GIFT and ET_COAL, to identify gift and coal, respectively.

Now over to gifts.c, the new compilation unit we've created to handle both our gift and coal entities. Once more, we'll see that implementing these objects is very simple. Starting with initGift:


void initGift(int type)
{
	Entity *e;

	if (giftTextures[0] == NULL)
	{
		loadTextures();
	}

	e = spawnEntity();
	e->type = type;
	e->x = stage.player->x;
	e->y = stage.player->y;
	e->dy = -6;

	if (type == ET_GIFT)
	{
		e->texture = giftTextures[rand() % NUM_GIFT_TEXTURES];
	}
	else
	{
		e->texture = coalTextures[rand() % NUM_COAL_TEXTURES];
	}

	e->tick = tick;
	e->draw = draw;
}

As this is a shared function for both the gifts and coal, we're passing over the type we want to create (either ET_GIFT or ET_COAL). We're loading our textures and spawning an entity, while setting the `type` to the value we passed into the function. Note how the entity has an initial `dy` of -6, so that it doesn't fall immediately. Instead, it's going to move up the screen a little, as if Santa has tossed it. We're then randomly assigning a gift or coal texture from either the giftTextures array or the coalTextures array, depending in the `type`, and lastly assigning the `tick` and `draw` functions. Simple enough.

The `tick` function follows:


static void tick(Entity *self)
{
	self->dy += 0.5 * app.deltaTime;

	self->y += self->dy * app.deltaTime;

	if (self->y + self->texture->rect.h >= GROUND_Y)
	{
		self->dead = 1;
	}
}

Here, we're applying gravity to the gift by increasing its `dy`, and then adding that to the gift's `y`, so that it accelerates. We're then testing to see if the bottom of the gift (according to the height of the texture) has struck the ground, and setting its `dead` flag to 1 if so. We basically want to destroy these objects if they land on the ground.

Next up is `draw`:


static void draw(Entity *self)
{
	blitAtlasImage(self->texture, self->x, self->y, 0, SDL_FLIP_NONE);
}

A standard drawing function here, where we're just rendering the gift, using its `texture`.

The last function we have is loadTextures:


static void loadTextures(void)
{
	int  i;
	char filename[MAX_NAME_LENGTH];

	for (i = 0; i < NUM_GIFT_TEXTURES; i++)
	{
		sprintf(filename, "gfx/gift%02d.png", i + 1);
		giftTextures[i] = getAtlasImage(filename, 1);
	}

	for (i = 0; i < NUM_COAL_TEXTURES; i++)
	{
		sprintf(filename, "gfx/coal%02d.png", i + 1);
		coalTextures[i] = getAtlasImage(filename, 1);
	}
}

Once more, we're just loading a series of textures: gfx/gift01.png, gfx/gift02.png, gfx/coal01, etc.

That's all there is to gifts.c for now! We now need a way to drop the gifts and coal, so it's over to player.c for the final tweaks.

Starting with `tick`:


static void tick(Entity *self)
{
	move(self);

	dropGift();
}

We're now calling a function named dropGift:


static void dropGift(void)
{
	if (app.keyboard[SDL_SCANCODE_J])
	{
		app.keyboard[SDL_SCANCODE_J] = 0;

		initGift(ET_GIFT);
	}

	if (app.keyboard[SDL_SCANCODE_L])
	{
		app.keyboard[SDL_SCANCODE_L] = 0;

		initGift(ET_COAL);
	}
}

This is a simple function that tests if we've pressed either J or L, and then calling initGift, passing over ET_GIFT or ET_COAL depending on whether we want to deploy a gift or a lump of coal. In both instances, we're clearing the control, so that the player needs to press it again to issue another deployment.

That's all there is to it! Once again, because of our ground work, adding in our gifts and coal is a simple process.

Of course, we need the gifts and coal to actually do something, other than be removed when they impact the ground. The point of our game is to throw these things down chimneys. So, in the next part we're finally going to implement our scoring mechanism, and allow gifts and coal to enter chimneys.

Purchase

The source code for all parts of this tutorial (including assets) is available for purchase, as part of the SDL2 tutorials bundle:

From itch.io

Mobile site