Author: David

About that Empire Map Generator

About that Empire Map Generator

The Circle data used in the Empire map generatorThis post refers to the c sources in the AboutEmpire.zip file in the Github C Games repository.

I first developed the algorithm in 1986 and wrote it in Z80 assembler. It was then rewritten in Turbo Pascal and used in both the Warlord and Quest postal games that are still run by kjcgames.com. It has been rewritten in C in the Empire game. So how does it work?

The idea is to generate continents. Typically between 2 and 3 continents between 1500 and 1800 squares in total on an 80 x 50 map. The map is made up of land squares and sea squares but starts out blank.

First I throw down 30 land points and 50 sea points. I.e. the program randomly picks points.

void AddPoints(enum loctype lt,int numpoints) {
  int i,x,y;

for (i=0;i<numpoints;i++) {
  do {
    x=Random(MAPWIDTH-40)+20;
    y=Random(MAPHEIGHT-40)+20;
    }
  while (map[x][y].locis != lctnull);
  map[x][y].locis = lt;
  genpointsx[pointindex]=x;
  genpointsy[pointindex++]=y;
  }
}

Some of the constants and the loctype enum are defined in common.h. The map itself is built up by adding extra points to each land point and sea point. I’ve defined an array of points in data.h that has 35 rings of points.  Well they’re more squares than rings.  That text file shown in the image is what these rings are derived from. I’ve translated all the points into 35 sets of X,Y offsets in data.h.

These points get added in layers. Starting with the first layer which has 8 points in it around the centre – that’s the A’s in the image, the next layer has 12 B’s and 4 C’s in it and so on.

But I only add a land or sea point if the spot its going into is empty; once it is defined as sea or land it can never change. So sea points and land points bump up against each other as these ‘circles’ expand and you get coasts and all sorts of interesting shapes. After that I fill in all empty spaces as sea, and the count up the connected land and sea squares.

If there are any tiny seas, i.e. less than 5 squares area they get filled in as land and any land point that isn’t surrounded by at least 3 other land point gets sunk. Then so long as there are the right number of continents and the total land squares is between 1500 and 1800, the map is accepted. If not a new one is generated. Adjusting the number of initial land and sea points helps to generate more acceptable maps.

I’m tempted to go Nuklear

I’m tempted to go Nuklear

Gallery Image of GUI developed with NuklearNuklear is a library that is a single-header ANSI C immediate mode cross-platform GUI toolkit. It lets you develop stylish and beautiful GUIs for your applications. It’s written in C but any programming language that can work with C such as C++ or Python can also use it.

Importantly, it also includes documentation so you can make use of it. The best software in the world is useless if you can’t use it and GUI toolkits tend to be a little bit more complicated than say a text editor.  This is nicely written, and though it’s just one document, it’s a long one!

It’s one thing to write a simple GUI as I did in that Empire game but mine was only 600 lines long and pretty rough looking. Nuklear is 18,000 lines long ie 30x as big.  If there’s one thing I’ve found from my software development experience, it’s that a nice looking piece of software will get away with having more bugs than something that looks not as nice.

 

I’m considering switching to C11

I’m considering switching to C11

Programming image
Image by Gerd Altmann from Pixabay

All C code I write in the books is currently to the C99 standard. All the compilers involved (Visual C++ on Windows and Clang on Ubuntu) support C99 but C11 support seems restricted to GCC and Clang.

Microsoft has traditionally supported C++ but their C support seems a bit grudging; realistically they don’t prioritise it which I can understand.

Given though that I’m not going to republish my first e-book for a while (I’d like to add a WebAssembly chapter or two first), I’m going to investigate whether it’s worth switching to C11 for the 2nd book. From what I’ve read all it needs is a flag to tll it to compile to C11 standards. This is for Clang.

-std=c11

But the other question is what will I gain by doing this and I can’t actually see there’s that much benefit.. I don’t need Unicode, I don’t think alignment will really make much difference. You can read about the C11 changes on WikiChip.

So I’ve made the decision. I’ll stick with C99 for now. But for an alternative view, I recommend Danny Kalev’s 2012 article on C11.

 

Other ways to time code

Other ways to time code

Stop Watch photo from Pixabay
Image by Free-Photos from Pixabay

As well as the hr_time code that I used in discussion of sdldemo SDL itself provides some other ways to time. If you are happy with millisecond level accuracy of timing, just call this function which returns an unsigned 32-bit (i.e. 0- 4 billion) giving the number of milliseconds since the SDL library was initialised.

SDL_GetTicks()

The link goes to the Wiki page on libsdl.org  for SDL_GetTicks().

As always, call it twice, once to get the start value and once to get the stop then subtract start from stop to get the elapsed time in milliseconds..

For some operations this can be easier to use. A frame is 16.666666 milliseconds so if your code runs in less than 16 milliseconds, it’s not going to cause problems. In my original Windows code, it ran is a fraction of a millisecond. Compiled C code really is fast and helped because the GPU is doing most of the donkey work!

There’s also a higher accuracy timer. This I guess is just a wrapper round the system call I call in hr_time.

Uint64 SDL_GetPerformanceCounter(void)
Which I haven’t used yet but which I guess returns a processor clock count. To measure time you need to call it twice (start and stop values as before) then divide by the frequency value returned from a call to

Uint64 SDL_GetPerformanceFrequency(void)

My computer returns a clock frequency of 3,500,000,000 clocks per second but the actual value is irrelevant just divide ((stop – start)/ frequency) to get the elapsed time in seconds.

Added Empire 9 to the C Games repository

Added Empire 9 to the C Games repository

Splash screen from the Empire gameBack in 2012/2013 I was writing the C/C++/C# column for About.com and I was doing games tutorials with SDL. This is an Empire type game, much like the Z80 game I mentioned in yesterday’s post except coded in C and with hexagons instead of squares.

It is not complete but includes a working map generator and a simple GUI that I devised based on a very crude OOP type of coding using function pointers and macros.

I’ve put it on the C Games repository and In the empire9src.zip (in the aboutempire.zip)  file you’ll see sdlgui.h and c. These implement it and (years ahead of Flutter and Dart!) it redraws the GUI at 60 fps.  The controls are built in a linked list of sdlcontrols.  This is a sdlbase which is the base for all controls.

#define sdlbase enum controltype ctype;\
int x,y,width,height,color,clickable;\
SDL_Color textcolor;\
void (*pRender)(struct sdlcontrol * self);\
void (*pFree)(struct sdlcontrol * self);\
void (*pClick)(struct sdlcontrol * self);\
void (*pPreClick)(struct sdlcontrol * self);\
struct sdlcontrol * nextcontrol

The four void (*..) are the function pointers. The pRender function draws the controls, pFree frees it up.. pClick handles clicks and PreClick provides extra functionality.

struct sdlcontrol { sdlbase; };
typedef struct sdlcontrol * psdlcontrol;
typedef char * pchar;

struct sdlbutton {
  sdlbase;
  pchar labeltext;
  int isDown;
  int countDown;
};

struct sdllabel {
  sdlbase;
  pchar labeltext;
};

Those are the definitions for sdlbutton and sdllabel and all controls have sdlbase (Everything in the big macro) and additional info.

This is the code that rendered a label.

void RenderLabel(psdlcontrol self) {
  int result,x,y;
  char buff[60];
  struct sdllabel * label= (struct sdllabel *)self;
  SDL_Rect rect = {(Sint16)self->x,(Sint16)self->y,(Uint16)self->width,(Uint16)self->height};
  x= self->x;
  y=self->y;

result=SDL_FillRect( screen, &rect, self->color );
  sprintf(buff,"%s",label->labeltext);
  ttf_print(x+2,y+2,buff,self->textcolor);
}

So every frame, the program would render all controls to the off-screen buffer by walking the linked list of controls and calling the pRender pointer for each. For buttons this would include a simple animation to show the button being clicked down and then released etc.

If you’ve ever wondered how a GUI is implemented take a look at the code. The sdlgui.c is less than 600 lines but manages to do panels, buttons, labels, checkbox, listbox and images.

Why I like C for creating games

Why I like C for creating games

Dark Empire ZX Spectrum gamePart of the reason is SDL which is a wonderful library and whose potential I have barely touched. I used to be an 8-bit games developer back in the 1980s, writing games for CBM-64, ZX Spectrum, MSX and Amstrad CPC-464.

I wrote those games in Z80 and 6502 assembly language. Thee were no libraries, no frameworks, no debuggers (lots of print statements) and when I first started, I wrote the games on the machines themselves.  If you got a crash, the computer would hang or reset and everything had to be reloaded from tape usually.

True story, I started by learning 6502 and when I came to learn Z80 I did it by writing a 6502 cross-assembler in Z80.  6502 is a very simple CPU with just 69 instructions. I was given the Z80 source for a text editor (Zen) and built the 6502 assembler into it.

Things gradually improved, we got development machines so we just needed a small loader on the target machine that downloaded the machine code from the development machine. That speeded up development enormously.

C is a very simple language and SDL can shift pixels very rapidly. I wouldn’t necessarily choose C for 3D games but for 2D arcade games, I think C is nearly perfect. With SDL, once you learn how to initialise it, load graphics (from disk to GPU), blit shapes and flip the screen you are 90% of the way there.

That image was one of the games I wrote in 1987, an Empire “Conquer the shrouded world” game where you are playing against a computer player. There’s six minutes of gameplay on youtube.

Update on the sdldemo

Update on the sdldemo

I’ve redone the hr_time,h and c files and am much happier with them now and also updated the code on github.  Apparently the reason for having <linux/time.h> as well as <time.h> and including both is because the <time.h> is set in stone and any additions have to be done as an extra include file. This is what hr_time.h looks like now.

#ifndef _timeh
#define _timeh 1
#include <linux/time.h>
#include 

struct _times {
  struct timespec start;
  struct timespec stop;
};

typedef struct _times stopWatch;

void startTimer(stopWatch *timer);
void stopTimer(stopWatch *timer);
double diff(stopWatch *timer);

#endif

 

I do like Visual Studio Code

I do like Visual Studio Code

Visual Studio Code MarketplaceWhen I wrote the Windows version of the book I used Visual Studio and it was quite excellent. But Visual Studio Code (VSC), the free cross-platform IDE is also very impressive.

Not only does it let you create your own extensions but you can even include debugging and visual debugging like Visual Studio.

I installed Clang and it’s associated debugger lldb. It is pretty powerful, The only thing that is a bit difficult with VSC is the learning curve for configuring builds, etc. With the Microsoft C/C++ extension there are four JSON files that must be configured for compiling, debugging etc.

The picture is from the website for the Visual Studio code marketplace. There are currently over 16,000 extensions most if not all (I haven’t checked them all!) are free and support virtually every popular programming language and probably one or two I haven’t heard of.

That Clang C compilation

That Clang C compilation

I spent about five hours trying to get the timing code to compile before I got it compiling and working. Now I’m used to the concept of include guards in C. Those are the #ifndef that you see like this:

#ifndef _timeh
  #include <linux/time.h>
  #define _timeh 1
#endif

But in the hr_time.c file these include guards are on steroids. Not only did I need to include <time.h>, I also had to include <linux/time.h> but with a couple of extra #defines in there. It doesn’t seem right and wasn’t needed with the Windows version.  I’d welcome any comments on this.

#ifndef _timeh
  #include <linux/time.h>
  #define __timespec_defined 1 
  #define __itimerspec_defined 1
  #include <time.h>
  #define _timeh 1
#endif

The sdldemo program with timing whown in the window caption.Without these, I’d get compile errors like __timespec redefined errors.

I’ve uploaded the source files and Visual Studio Code JSON files for this in the file asteroids_ch25.zip in the new repository for the Learn C on Linux Ebook

So feel free to try it. The only difference between this and the version shown in an earlier post is the time (in the window caption) to draw all 100,000 rectangles,  You’ll need to install SDL2 if you want to compile and run the program.

The joys of Linux C Compilation

The joys of Linux C Compilation

I’m slowly working my way through 30 odd examples of C code that I wrote for the first 20 chapters in my Ebook., And finding odd compile errors. Here’s an example.

I’ve rewritten my stopWatch object for high-precision timing. This is the header.

#include 

struct _stopWatch {
  struct timespec start; 
  struct timespec stop;
} stopWatch;

typedef struct _stopWatch stopWatch;

void startTimer(stopWatch *timer);
void stopTimer(stopWatch *timer);
double diff(stopWatch *timer);

It won’t compile, and keeps on complaining that timespec is an incomplete type. I saw one solution which was to redefine timespec like this:

struct timespec {
  time_t tv_sec; /* seconds */
  long tv_nsec; /* nanoseconds */
};

But that got Clang wound up about timespec redefined errors. I searched and searched and eventually found the answer. Instead of

#include <time>

Use this as well

#include <time> 
#include <linux/time.h>

Simple when you know how!