1. Computing

How to add a shroud and cities to the Scrolling Map in SDL for the Empire Game


Shrouded Map with cities

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

The sources and compiled code plus all supporting dlls and graphic files can be downloaded from the link below. To run the generator unzip everything in the binaries into one folder.

Note, if you are creating your own SDL project (for these sources in Visual Studio 2010 or Visual C++ Express 2010), then you should see How to setup Visual Studio 2010/Visual C++ 2010 Express with SDL.

As part of the Empire game development, we saw in in the Empire Map Generator, how to generate a game map. In the previous tutorial, we produced a scrolling hex map from that generated map. In this tutorial we add a shroud and 50 randomly placed cities.

Last time I had a slight bug with right click drag. It was a stupid error caused by inadvertently modifying the SDL_events.h and changing the type and size of one of the event fields from Sint16 to int. Restoring from an original fixed it and I made sure that all the SDL include files were made read only.

If you use a version control system and add all of the SDL include files then that should also prevent accidental edits.

Continuing with the second Scrolling Map tutorial, this time I'll add a map shroud and cities.

Adding a shroud

A shroud hides the parts of the map that you haven't explored. It's the gray part in the image above. As your units move across the map they unshroud locations and you discover uncaptured cities or enemy units.

As the game can hold up to 7 enemy players and you (8 bits per locastion) we use one byte for every location. As you units move they explore and see (i.e. unshroud) all hexes within two of each of your units, or three of a city that you own. So capturing a city unshrouds all hexes within 3 of the city.

We also use another byte for every location viewed. This is a concept by which you only see enemy units within three hexes of a city and two hexes of one of your units. You may see unshrouded terrain on the main map but you won't know that there are enemy units present unless they come close to your units or cities. It's the fog of war.

The shroud is just a grey hex. Enemy ai will only react to your units if they view them, so it's important to track shrouded hexes for all players, computers or human. I've used character 40 in maphexes1.gif as the shroud.

At this point it makes sense to hold each location as a struct. So map[][] is now a 2D array of struct hex where a hex holds the map type, viewed, explored and loc as Uint8, i.e a byte.

struct hex {
Uint8 maploc;
  Uint8 explored;
  Uint8 viewed;
  Uint8 loc;

In the struct maploc is the character (i.e. value of the hex graphic - remember there are 4 open, 4 mountains etc) whereas loc is the value of the enum loctype; I added a block of code to output the values of loc in map2.txt. That's commented out but if you want to see it, uncomment it, compile and run.

As we have no units yet, I've created a ShowRandomLoc() that randomly sets the 5 x 5 locations to have the explored bit 0 set to 1. It calls exploreround() with the coordinates and range. This sets the explore bit for the player (bit 0) and then loops through each of the 8 locations around it determining if it's a valid hex through calling the function isvalidhex(). This stems back to the brick wall.

7  0  1  
6  x  2  
5  4  3  

  7  0  1  
6  x  2  
  5  4  3  

On an even row, the locations in directions 1 and 3 are not part of the six surrounding the hex marked x. On an odd row, locations 5 and 7 aren't near. The function isvalidhex() handles this. The exploreround() function uses the range parameter to recursively go out as many hexes as specified. It's a little inefficient as it checks some locations several times over.

m = &map[x1][y1];
(*m).explored |= 1;

This gets the address of a particular location in the map[][] and then or's in 1 to set the explored flag for the player. If you don't want the shroud while testing, set the #define SHROUD value to 0. If you have the shroud, press t will punch random sized holes 1-4 hexes in radius. Press the S key to restore the shroud to pristine condition.

Adding Cities

We'll be adding up to 50 cities on the map with the first 20 guaranteed to be by the sea and no two cities within 4 locations of each other. I modified map.txt to remove the one city that was included there to show that the graphics worked.

We need to store this information about cities in a separate array of city structs.

  • x and y coordinate
  • Owner (0= player, 1-7 = ai player, -1 = unowned)
  • Producing (an enum)
  • Turns to Produce.
  • Target x,y- Where newly produced units go (default= nowhere -1,-1)
  • By Sea = 1- true)

Here's a first cut. When we introduce units, I'll changing producing to an enum.

struct city {
    int x,y,owner,producing,turnstoproduce,bysea;
    int targetx,targety;

The easiest way to way to find random city locations is just generate an x,y and see if it is land (== ltopen) at least two of the six surrounding hexes are a sea loc. Be sure to check map[][].loc not maploc!.

I've added fifty cities. Press the a key (but only once) with this version of the code to add them. If you have the shroud enabled, this will call exploreround() each city so you can see them. Press t to add a few more 'holes'.

I used the red city graphic for the first 20 cities (by the sea) and yellow for the rest. A yellow city can be placed by the sea but only the red ones are guaranteed to be there.

The addcity() function tries to add a city and if it's not the first one, it calls CityNotTooNear() to check that it's 16 (square of 4) locations away from any other city. It's just as easy to check against the square of the distance and saves time calling the square root and dealing with floats.

There's no checking what to do if it can't place all 50 and this is something I'll have to deal with when the map generator is included in the game.

This concludes this tutorial. In the next one, I'll be selecting hexes, and adding armies.

  1. About.com
  2. Computing
  3. C / C++ / C#
  4. Programming Games
  5. Scrolling Map for Empire Game 2

©2014 About.com. All rights reserved.