Mathias Dierickx

Engine programmer


CloneCraft - A Warcraft2 Clone

A clone of the popular Warcraft2, made entirely in C++ using SDL to display 2D textures on screen.

About the project

TileSet

The project was created from scratch, using only a simple game loop and all other code was custom made for this specific game. All assets are from the opensource FreeCraft project, I don't own any of the assets in this game.

One of the features I spent a lot of time on was creating a way to load maps in an easy way. I ended up creating an algorithm that can load the correct tile textures from a spritesheet using a simple .JPG image. (see image on the right)

The next challenging part was the movement of the units, they could not run through each other and had to be able to move with up to 9 units in one squad. This turned out to be more of a challenge than expected. Just using an A* pathfinding algorithm wasn't enough. Units have to keep checking if the next tile in their path is still free, if it is they "lock" the tile so that no other unit can walk to the tile. If the tile is occupied by either a unit standing on it, or another unit Locked the tile, the Unit has to find another way around that tile. This detour is chosen so that the Unit can get to the shortest path again in the shortest distance possible. Once this was implemented, I had to make sure land units can't walk on water, and air unit can fly over both water and land units. This was done by making 3 movement layers. These layers are encoded in the tiles, where every type of tile knows if a land, air or water unit can walk over it.

There are a lot of different types of units and buildings. All these units can be upgraded and some of the buildings can also be upgraded to boost stats or to unlock more units and more advanced buildings for the player to use. This required the implementation of an upgrade tracker. This class keeps track of the built buildings and the researched upgrades. This makes sure advanced buildings get unlocked once the requirements are met and the upgraded units deal more damage depending on the researched upgrades.

Code snippets

The following two code snippets are the core of the level loading algorithm. The first function is used to get the color from a certain pixel of the image, this function is used in the main algorithm to get the color of the pixels and store them in a 2D array representing the level. Once all colors are known, the function in the second snippet wil create the actual tyle objects with the correct settings, depending on the color of the corresponding pixel. Of course, using color data for the purpose of storing just what type of tile we need, is a waste of memory. I did it this way, because I wanted an easy way to edit the terrain as I was designing the levels. It could also be done with for example a csv file containing just an index from 1-*NrOfTileTypes. However, this solution makes it harder to actually design the level. An intermediary solution would be writing a program that converts a png image to the described csv file, to save on memory and time when loading the level as I would skip loading and reading the texture and instead of colors I would need just one short value to represent all possible tile types.

The final step of the algorithm is checking what type the surrounding tiles are, so that the edges between types can automatically be generated.

This final code snippet is the base code that makes sure the units don't collide and walk through each other, while air units can still fly over all other units. When this function gets called, the units has a shortest path from when the movement started to its destination. The function constantly checks if the unit passed the first tile in it's path. If it did, we check if the next tile is still passable for the current unit type. I this is the case, we can lock this tile and unlock the one we were just on. If it is not free anymore, it will keep checking subsequent tiles on the shortest path until one free tile is found. If such a tile is found, we calculate the shortest path to it in the current map state and prepend that to our previous path. I there is not a single tile left in the path, or all tiles in the path are occupied, we stop the unit and put it in its idle state.