so_long: making a game without a game engine

so_long: making a game without a game engine

I have experimented with game engines before and even developed some 3D games, that's why I got so excited for this project.

So my next project seemed pretty simple: make a 2d game where you need to collect all the collectibles before going to the exit. It's simple but time-consuming, especially because we are not going to use a game engine, we are only allowed to use a small API in C called minilibx used for rendering graphics and managing windows.

So I got the idea of the game: I remembered the time I stayed at home during the pandemic and decided to make the game about that, you've got to collect the face masks and avoid the viruses. And of course, the player is a character from Among Us, the game I played the most with my friends during the pandemic.

First friends reunion after the pandemic. 2020

With that in mind, I started to code.

The map

The map can be created by the user, in a file ending with .ber. So I started coding the map validations. Here are the rules:

  • The map has to be rectangular.
  • The map must be closed/surrounded by walls.
  • It can't have extra characters, other than the game components.
  • There has to be a valid path on the map.
The last is by far the hardest rule.

That means that if the player, a collectible, or the ending is surrounded by walls or by enemies, the player will not be able to end the game.

So for that, I had to write an algorithm composed of a recursive function that would go through the whole map, check if it could collect all the masks, and if it was able to touch the ending. Here's the code:

int	path_checker(char **map, int y, int x, t_algo *algo)
{
	if (algo->c == 0 && algo->e == 1)
		return (1);
	if (map[y - 1][x] == 'E' || map[y + 1][x] == 'E')
		algo->e = 1;
	else if (map[y][x - 1] == 'E' || map[y][x + 1] == 'E')
		algo->e = 1;
	if (map[y][x] == 'C')
		algo->c -= 1;
	map[y][x] = '1';
	if (map[y - 1][x] != '1' && map[y - 1][x] != 'E')
		path_checker(map, (y - 1), x, algo);
	if (map[y + 1][x] != '1' && map[y + 1][x] != 'E')
		path_checker(map, (y + 1), x, algo);
	if (map[y][x - 1] != '1' && map[y][x - 1] != 'E')
		path_checker(map, y, (x - 1), algo);
	if (map[y][x + 1] != '1' && map[y][x + 1] != 'E')
		path_checker(map, y, (x + 1), algo);
	if (algo-> c == 0 && algo->e == 1)
		return (1);
	else
		return (0);
}

In this code, c is the collectible counter, and e is the exit counter, when it passes next to the exit, it sets e to 1, and when it collects an item, it subtracts 1 from c.

At the end, it checks if the exit counter e is 1 and the collectible counter c is 0, which means the player can collect all the items and go to the exit.

The graphics

With the map validation done, I started preparing the graphics of the game. I went to itch.io to search for some free assets I could use. There I found the box, the armchair and the wooden floor. And for the player, the face mask and the virus, I could only find searching on Google.

Since I grabbed the images from different sources, they all had different sizes, but for my game, I need them to be all 80x80. So I had to resize them and convert them to the format .xpm which is the only one that the API minilibx accepts.

So, after writing some more code to render the images on the window and map the keys pressed on the keyboard. Voilá! The game is working.

1111111111111          1 for the boxes.
1000C00000C01          0 for empty spaces.
1X1C001101101          P for the player.
100000X000001          C for the collectibles.
10P00110X0C01          X for the enemies.
1000011E00001          E for the exit.
1111111111111

Map shown on the gif.

Of course I still had a lot of work to do to fix memory leaks and make sure the game runs smoothly. You can check the code and play the game here:

GitHub - marcioflaviob/so_long_42
Contribute to marcioflaviob/so_long_42 development by creating an account on GitHub.