Category: Techniques

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.

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!

The missing SGN function

The missing SGN function

Both C and C++ lack a sgn (short for signum apparently!) function (unless C++ has added it in recent changes. It’s also available in Boost but this blog is not about C++ so who cares!

Sgn() for those who don’t know is a function that returns -1 if the passed in int value is negative, 1 if the value was positive or 0 otherwise. Even BASIC includes it but not C.

However it’s easy to add. Something like

int sgn(in x) {
  if (x=0) return 0;
    else
  if (x>0) return 1;
  else 
    return -1;
}

Of course if you are using longints or floats or doubles, you have to write those as well. However an alternative is to make it into a macro.

#define sgn(x) (x < 0) ? -1 : (x > 0)
int a = sgn(10);

The only downside if you make lots of calls to sgn() is that it will slightly bulk up your code compared to calling it as a function but it will run fractionally faster!

High speed timing in C

High speed timing in C

One of the things I like doing is timing code. Not to benchmark it per se, but to get an idea of performance. I have a small set of functions to do this on most CPUs for the last ten or fifteen years. It uses the high frequency clock, which. on my PC (a five year old I7-5930K), this counts at the rate of 3,500,000,000 per second.

You just read this timer twice, subtract the difference and then divide by the frequency (3500,000,000) to get a time in fractions of a second accurate to nano-seconds. (10-9 seconds).

Here’s the code for Windows. It’s in the several of the ebook chapters, e.g. chapter 48 (download the file asteroids_ch48.zip and unzip) . Or you can just copy from here.

hr_time.h

#include <windows.h>

typedef struct {
LARGE_INTEGER start;
LARGE_INTEGER stop;
} stopWatch;

void startTimer(stopWatch *timer);
void stopTimer(stopWatch *timer);
double LIToSecs(LARGE_INTEGER * L);
double getElapsedTime(stopWatch *timer);

and hr_time.c

#include 

#ifndef hr_timer
#include "hr_time.h"
#define hr_timer
#endif

void startTimer(stopWatch *timer) {
QueryPerformanceCounter(&timer->start);
}

void stopTimer(stopWatch *timer) {
  QueryPerformanceCounter(&timer->stop);
}

double LIToSecs(LARGE_INTEGER * L) {
  LARGE_INTEGER frequency;
  QueryPerformanceFrequency(&frequency);
return ((double)L->QuadPart / (double)frequency.QuadPart);
}
double getElapsedTime(stopWatch *timer) {
LARGE_INTEGER time;
  time.QuadPart = timer->stop.QuadPart - timer->start.QuadPart;
return LIToSecs(&time);
}

Use it like this:

stopWatch s; // declare a stopwatch variable

startTimer(&s);

// your code to be timed here

stopTimer(&s);

printf('It took %10.6f secs',getElapsedTime(&s));
More on pointers in C. The use of typedef

More on pointers in C. The use of typedef

Asteroid about to be destroyedThis bit is slightly controversial. I find all the * makes it harder to read code so I use typedefs to hide them. Here’s an example from the game. Try replacing every pbte with byte * and see if reading it is harder for you.

typedef byte * pbyte;

// mask arrays
byte bulletmask[1][3][3];
byte plmask[24][64][64];
byte a1mask[24][280][280];
byte a2mask[24][140][140];
byte a3mask[24][70][70];
byte a4mask[24][35][35];
byte alienmask[64][64];

pbyte GetMask(int type, int rotation, int size) {
  switch (type) {
    case tAsteroid: // asteroid
      {
        switch (size)
          {
            case 280:
              return (pbyte)&a1mask[rotation];
            case 140:
              return (pbyte)&a2mask[rotation];
            case 70:
              return (pbyte)&a3mask[rotation];
            case 35:
              return (pbyte)&a4mask[rotation];
          }
      };
    case tBullet: // bullet
      return (pbyte)&bulletmask;
    case tPlayer: // player
      return (pbyte)&plmask[rotation];
    case tAlien:
      return (pbyte)&alienmask;
    } 
  return 0; // null - should never get here!
}

In my post about collision detection I mentioned getting mask bytes. This function GetMask returns a pointer to a byte (i.e. the first byte in a particular mask for a particular type of object (asteroid, bullet, player, alien) and for asteroids and the player a particular rotation. The many (pbyte) are needed because the arrays have different sizes. There are 24 player and asteroid masks.

A look at pointers.

A look at pointers.

You cannot be a C programmer without using pointers. It’s the one feature of the language that makes possible much of what you can do in C. Pointers seem to scare novice programmers and it’s true that you can crash a program if you make a mistake, but otherwise they’re not that bad. Pointers as parameters in functions let you change the value of an external variable.

A pointer is just a variable that holds the address of another variable. So here’s my take on pointers.

You define a pointer as a pointer to a variable type like a pointer to an int or a char. There is also a “wildcard” where you define a pointer to a void. That has its uses when passing general pointers into functions. With types, the C compiler can verify assignments.

[perl]int * pInt; // pInt is a pointer to an int
char * pChar; // pChar is a pointer to a char
int a;

void ZeroInt(int * pInt) {
if (pInt) // Check pointer does not have a null value
*pInt = 0;
}

ZeroInt(&a); // Sets a to 0.[/perl]

That ZeroInt() function is a long-winded way of setting whatever int variable it is called with to zero. Yes you can just do a = 0; but that misses the point. What if a was a struct and the ZeroInt was a function to initialise all the fields of the struct?

How pixel perfect collision detection works

How pixel perfect collision detection works

Asteroid and player ship about to collide near an explosionsThere are four types of moving object in the games. Asteroids in four sizes from 35×35, 70×70, 140×140 and 280×280 pixels, the player’s ship (fits in 64 x 64 pixels), alien ships (also in 64 x 64)  and a bullet which is solid 3×3 pixels with the four corners empty.

As these move around the screen at 60 frames per second, they will come into contact and the collision detection has to figure out when they hit or miss.

To make it more complicated, the asteroids and player’s ship come in 24 rotations, each by 15 degrees so detection has to take that into account. The image shows an asteroid just about to hit the player’s ship.. At the bottom you can see where another asteroid has been blown up (the 50 is the score) and there’s a bullet to the right.

The detection occurs in several stages. First each object has a bounding square.This shows the bounding boxes for the player's ship and an asteroid This is an invisible square that just fits round each object. For the player’s ship it’s 64 x 64 and it corresponds to the sizes of each asteroid. As the image shows, the two bounding boxes overlap and it’s in this overlap rectangle that we have to check for a possible collision.

A large asteroid and the cells it overlapsFirst things first. Every frame all objects are moved and we have to detect if there’s a chance of a collision. This is done by dividing the entire playing area (set in the book to 1024 x 768) into 64 x 64 pixels cells.  I chose that as a convenient size. Once the object’s new x,y location has been calculated, I determine which cells it overlaps.

The player’s ship can fit completely into one cell but most times it is either overlapping two or four cells. Even a 3 x 3 bullet will occasionally overlap two or four cells but most of the time it will fit completely in one.  The largest Asteroid (280 x 280) always overlaps five or six cells in each direction so it gets added into to 25,30 or 36 cells each frame.  The image shows the grid of 64 x 64 cells and the asteroid overlaps 25 cells, the player’s ship just overlaps 4 cells. The number is a count of the number of overlapping item in each cell.   It’s the bounding box size that determines if it overlaps which is why the top left and bottom right empty cells of the asteroid still show 1.

In each cell, I keep a list of objects that overlap that cell. The first step is scanning all cells with overlapping objects in to see if there are two or more objects overlapping in that cell. The SDL library includes a function SDL_IntersectRect()  You pass in the two bounding rectangles of overlapping objects and it returns a rectangle of the intersection, which corresponds to the overlap in the image above. If there are multiple objects in a cell e.g. four then you have to check to see if any of those (1,2), (1,3), (1,4), (2,3), (2,4), (3,4) overlap.

A text file representation of a maskThe next bit is what makes it pixel perfect. For every object and its rotations, I have created a mask. It’s a file of bytes with a 1 value corresponding to every coloured pixel in the object and 0 to empty pixels.

I have stretched this image to make it the same aspect ratio and it shows 0s and 1s in the player’s ship mask.

The collision detection algorithm processes the intersection rectangle and calculates where each pixel in that rectangle falls in the corresponding mask (adjusting for rotations) of each object.  If either mask pixel is 0 then no collision occurs but if both are 1 then bam!

Although I could have used a mask of bits, it was quicker to use bytes.

During development I wanted to verify that it was pixel perfect, so I disabled explosions and instead when two pixels overlapped, I output a green pixel to highlight it. The image shows the player’s ship passing through an asteroid!Showing pixel perfect touching