1. Computing

SDL Empire Tutorial Seven - Integrating the Map Builder

Setting Up the Game

By

Empire with Map Generator

This is the latest tutorial about developing the Empire game. If you've found this article first, please see part one. Here's more information about the Empire Game.

In the previous SDL Gui tutorial 6 I added a splash screen. In this tutorial, I'm integrating the map generator with the game display code. No more loading maps from a text file. It now generates a full map with cities by itself.

In How to generate a map ...Part One and How to generate a map ...Part Two, we saw a map generator and adding cities.

In this tutorial I've taken the source code from the map generator part two and combined it with the SDL Empire game code so when it runs, it will generate a new random map and add cities. In the next tutorial it will add your starting army and reveal your starting city.

Latest Code

  • Download Source Code File (Zip).
  • Download binaries (All Exe + SDL dlls + graphic files etc) zipped up. Just unzip everything into one folder. It should run. You shouldn't need SDL installed unless you are developing it.

Merging Two Working Programs

One of the worst aspects of C (and C++) is the way multi-file programs are put together. This was a problem that was solved thirty years ago in Turbo Pascal with units; compilation units that had interface and implementation sections. Types, variables and functions meant to be exported were declared in the interface section and then fully defined (for code) in the implementation section. That let the linker be very smart (and fast) about excluding unused code from the final exe.

But we don't have that in C or C++ so you need a bit of thought. I like to structure my C code so that major functionality like the map generator, SDL GUI are in their own files and have a header exporting the types etc.

In C you have declare variables in one place and then refer to those variables if used elsewhere. In my case, I have mapgen.c for generating the map and empire.c for using it. As the map is an array [][] of structs, that struct and the array have to be declared somewhere that can be used by both mapgen.c and empire.c. So I created common.h and moved many declarations in there.

Refactoring C programs like this is messy and it took me 2-3 hours to move declarations around and also tidy up the code. The AddCities code in empire.c was better than the one in mapgen.c so I moved it in there.

A deficiency with the C compiler is that it get upset with the same header files being included more than once. If it does, you get duplicate declaration errors. So you'll see lots of guard code like this which only lets a header be included once.

#ifndef COMMON
#include "common.h"
#define COMMON
#endif

If I wanted to declare something in a source file and not be used from outside that file then I could declare it static, but so far I haven't had to do that. Anything else can be accessed from other files using the extern prefix. So the map is declared in empire.c like this:

struct hex map[MAPWIDTH][MAPHEIGHT];

The only other parts of the program where the map needs to be accessed is in mapgen.c for the map generator and in common.c for the exploreround() function, so it is declared in common.h. This declaration looks like this:

typedef struct hex maptype[MAPWIDTH][MAPHEIGHT];
extern maptype map;

If you leave off the extern, then there will be two map variables and the linker will get upset.

I used a typedef to remove the need for the struct prefix but

extern struct hex map[MAPWIDTH][MAPHEIGHT];

will also do if you prefer.

I also changed the loctype enum (and everywhere it was used) to a char and defined sea, open, mountains etc with a #define. This was because the map generator used one set of mappings (the loctype enums for the terrain types) then output a map.txt file using a set of chars (~ for sea, . for open, ^ for mountain etc) which was loaded by the main program.

It made sense just to use these chars internally instead of the enum. However the generated map still needs processed so that the hexagons are correctly mapped. This was previously done in the LoadMap function which no longer exists and is now done in a function ProcessMap().

So everytime a map is generated by BuildMap() you should call ProcessMap(). I've added a New Map button which calls a function to call these so you can instantly get a new map with one click.

That completes this refactoring tutorial. In the next one, the units are added and hopefully a new nicer looking hex map set! Note that this version now outputs map.txt when BuildMap() is called. It's just for debugging purposes.

  1. About.com
  2. Computing
  3. C / C++ / C#
  4. Programming Games
  5. Empire Tutorial seven - Integration

©2014 About.com. All rights reserved.