Category: Game

Building Asteroids on a Raspberry-Pi

Building Asteroids on a Raspberry-Pi

My asteroids running on a Raspberry-Pi 3B+Silly me completely forgot that Raspberry Pis have a different CPU architecture compared to my PC. You just get used to something working on Linux and it was only after copying and it didn’t run that I realised my mistake. So I now have to recompile Asteroids (from Chapter-48.zip).

I’ve had a Raspberry-Pi 3 B+ for a year and wanted to run the Linux asteroids on it, now that I have it working on Ubuntu.

To do that I had to setup  Pi, running Raspbian downloaded from the Raspberry Pi website onto my Windows PC and then I used Win32 DiskImager (free Windows software) to burn the Raspbian OS onto a SD Card. Raspberry-Pis boot from SD Cards and the better and faster the SD card, the quicker the OS runs. Get a class 10 with A1 SD Card if you can.

After the Pi booted and Raspbian was installed and configured I had to enable SSH on the Pi; it’s disabled by default.

So now my PC was talking to the Pi using the excellent free WinSCP.  I copied all the files over, including the masks, sounds and images folders and all the source code and my exe built on Ubuntu which was the wrong file type. (Trying to run Intel code on an ARM- good luck with that!)

Now it turns out that the Raspbian version I installed (I’d gone for the Raspbian Buster with desktop and recommended software-2.5 GB download) included the non-dev version of SDL2. But as I needed to recompile the whole program, I had to install Visual Studio Code, Clang and the dev versions of SDL2, image and mixer.

Visual Studio Code on Arm?

Haedmelted VS Code running on Raspberry Pi 3b+Microsoft don’t do an official version for Raspberry-Pi or other ARM boards. However I discovered that a developer called Jay Rodgers has taken their source code (VS Code is open source) and  you can get a version from his site. It’s very usable on the Pi. Almost but not quite identical.

After installing the dev versions of libsdl2, image and mixer, I was almost able to compile it. I’d installed Clang but unlike the version on Ubuntu which was Clang-6, the version on Raspbian (based on Debian Buster) is Clang-7.

This means you have to edit the tasks.json file in the hidden .vscode folder. On line 25 where it says “command”: change the path to “/usr/bin/clang-7”.

That built ok, but when I ran it, it stopped with an error in the errorlog.txt file. For some reason, it failed loading the file “masks/am2.msk”.  Now I’d had no errors copying files from Windows to the Pi. This had been a very intermittent problem when copying several files in one go from Windows 10 to Ubuntu running under Hyper-V. Occasionally it would come up with some weird error but usually copied OK on the second go.

Despite several attempts, I could not get it to load that mask so as a temp fix I commented the line out. This means that one of the four asteroids sizes can never collide with anything. But it now ran.

However, I’m only getting about 25-27 fps with it in the early levels, not the 60 fps that I get on Ubuntu on other hardware. Given that the bulk of the work is blitting graphics, I suspect the GPU is just a bit under powered. Apparently on the Raspberry Pi 4, the GPU is newer and twice as fast as on the 3B+ so I’ll have to try it on a 4 when I get one. But the game works and is just about playable.

Now I’ll have to try and figure out why it won’t load that one mask. This has the makings of an interesting bug…

 

Laptop vs Hyper-V

Laptop vs Hyper-V

Laptop
Image by Engin_Akyurt from Pixabay

As a way of checking that the stuff I’m posting on GitHub, I’ve been downloading them onto a laptop and testing them.

The laptop is a seven year old Toshiba that was re-purposed from Windows to Ubuntu 18.04 LTS, the same version as I’m running in a Hyper-V session on my main development PC.

Although the laptop is older and only running an i3 chip, it still outperforms the game code running under Hyper-V code on my five year old i7-5930K PC.  I think the difference is purely because the GPU code is run in a software layer not on the real GPU. But I might be wrong.

When I tested it with 255 asteroids on screen the laptop still maintained 60 fps but the Hyper-V running version dropped below 60 fps once there were 125 asteroids on screen. I have a suspicion that C code that isn’t calling any SDL routines would run faster under Hyper-V because it’s virtualised.

Just a picture post!

Just a picture post!

Lots of collisions here with explosions turned offIn the chapter 42 of both e-books when the first collision detection is introduced, I added a SHOWOVERLAP #define. If this is uncommented, instead of things blowing up, it shows every pixel where two objects pixel’s overlap in bright green.

In the picture above you can see the player ship in the centre and all those green bits where things overlap. You don’t normally see this and it is so intensive that it drops the frame rate from the usual 60 fps to about 3 or 4. But I think it’s quite cool!

 

SSSnakes – a game for the next Ebook

SSSnakes – a game for the next Ebook

Screenshot of snake gameI’ve done a snake game in the past for About. That’s the picture and today I’ve uploaded it complete with source to Github. The thing with snake is, everyone knows it, its old hat and not particularly exciting.

Back in the early 80s the same was true about Breakout games. It was a common trope for game programming, bouncing a ball off a bat to break through a wall.

But then in 1987 along came the Arkanoid game which could be best described as Breakout re-imagined.  More balls, special bricks when when hit gave different features. It made Breakout games cool again for a few years.

So Ssnakes, is my name for a re-imagined snake game.  We’ll throw away losing your life when the snake hits a wall or itself. Only if your snake runs out of space is it dead, or if it is killed by an enemy. And as it travels around it picks up food which gives it energy. You can burn this energy is making it longer, moving faster or .. spawn off a new snake! Also you can attack enemy snakes – spitting venom directly ahead or sinking fangs into an enemy body if  your snake’s head is next to it.

Having 2, 3 or 4 snakes on the go will make it a bit more stressful to control. You only lose a life when you only have one snake left in play and you lose it.

Plus instead of a plain empty arena there will be a few static objects in it.

 

Linux E-book Progress

Linux E-book Progress

Screenshot of the chapter 28 executableMy Linux rewrite continues with progress as far as chapter 38.

This is the first Linux version of asteroids on the left and is a demo of the text writing routines and also loading images from files.

It;s drawing all digits from 0 to 99 at random locations on the screen every frame.

The number at the top is how long it takes to output the text. That value if you can’t read it is 0.000622, which means it takes 622 microseconds to output 100 numbers or 6.22 micro-seconds each.

This is the routine that does that.

void RenderEveryThing() {
	int atX, atY;

	renderTexture(textures[PLBACKDROP], 0, 0);
	startTimer(&s);
	for (int i=0;i<100;i++) {
		atX = Random(WIDTH-50) + 1;
		atY = Random(HEIGHT) + 20;
		TextAt(atX, atY, SDL_ltoa(i,buffer,10));
	}	
	stopTimer(&s);
	SDL_RenderPresent(renderer);
	frameCount++;
	UpdateCaption();
}

The most recent uploaded code version (chapter 37) lets you move the player’s ship around (press q, w or ctrl) , fire bullets (space bar), press a to see random asteroids rotating and moving round (and off) the screen. Press the b key to blow up a few asteroids with explosions and sounds. Enjoy!

Zipped up source code, graphics etc from the forthcoming Linux book can be downloaded from Github.

My next Book – Match three

My next Book – Match three

I’ve been thinking about doing a 3rd book – something like ‘More C Games, design and programming’ which would have three games, each with a design and then implemented with explanations and bits of source code and all on Github.  The first game is possibly going to be a Match Three game.

Match tree gameMatch Three games have been around for the best part of a decade and have a basic mechanic of swapping two adjacent pieces to make a line up of three, four or five pieces which get removed.

What makes it more challenging and interesting is the almost limitless number of mechanisms you can build on. For instance when you clear four or five you get special items that when swapped with another special item do something interesting. Or could be you have to get a set of special items and so on.

Or you might have special levels where you have to clear all of one particular shape within a time or Boss levels where the baddy is continually adding hard to remove pieces that clog up the game, or you might have a rotate button that flips the board 90 degrees so you can get rid of hard to remove pieces by having them drop into special buckets beneath the board.

Now I just have to come up with two more games. Suggestions welcomed!

Using recursive fill to count maps

Using recursive fill to count maps

Terrain hexagonsIn the Empire game (yes, just one last mention!) during the map generation the program counts up the size of individual islands and sea areas. This is don by recursion and quite useful. Otherwise, the usual place you see recursion mentioned is in calculating factorials and Fibonacci sequences.

The map struct holds not only the terrain type and other information but a continent number. This is set initially to 0.  After the land and seas have been generated, the program picks a random land point on the map (just keep picking a random location until it has land with a continent number of 0).

It then counts by calling itself 8 times. It calls itself recursively at location y,x with directions (y-1,x-1) that’s NorthWest, (y-1,x)  and so on round to West (y,x-1).  But it only does it as long as each of those locations is land type with a continent number of 0. And as it does it, it sets the continent numbers in each location to 1 for the first continent and so on.

This recursive algorithm means that every contiguous land location gets reached. A similar thing is done with seas and lakes but you have to be careful that the stack is large enough.

void FillIn(int x,int y,int locis) {
  if onMap(x,y) {
    if (locis==map[x][y].locis && map[x] 
 [y].continent==UNALLOCATED) { 
      map[x][y].continent=numconts;
      allconts[numconts].count++;
      FillIn(x-1,y,locis);
      FillIn(x+1,y,locis);
      FillIn(x,y-1,locis);
      FillIn(x,y+1,locis);
      FillIn(x-1,y-1,locis);
      FillIn(x+1,y-1,locis);
      FillIn(x+1,y+1,locis);
      FillIn(x-1,y+1,locis);
    }
  }
}

This is used for both land and sea, so locis can be either. It’s an efficient algorithm and quite quick.

Those graphics? They were the initial hexagon graphics…

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.

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.

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.