Category: Game

Using small delays in C with SDL ticks

Using small delays in C with SDL ticks

Asteroids game - player ship rotationRunning a game at 60 frames per second means that handling things like key presses can be interesting. In the game, I call various SDL functions and via a giant switch statement set flags. Then later in the game loop, those flags are used to determine actions

So if you press Q to rotate the player ship anti-clockwise (counter-clockwise to yanks!) without some limiting thing, it would whizz round through 900 degrees each second. (There are 24 rotation angles for the ship, each 15 degrees. 60 x 15 = 900) .

I use a very simple technique to limit it. SDL has a function called SDL_GetTicks that returns the number of ticks since SDL was initialized in the game, i.e. when it started running. A tick is 1/1000th of a second, i.e. a millisecond. By calling this function twice, you can measure a time period. It’s not as precise as the nanosecond CPU clock that I use but for the kind of delays I’m talking about it is more than sufficient.

This is the code that is called each frame in the game loop.

void RotatePlayerShip() {
	if (rotateFlag && (SDL_GetTicks() - rotTimer > 40)) {
		rotTimer = SDL_GetTicks();
		if (rotateFlag == 1) // CounterClockwise 
		{
			Player.dir += 23;
			Player.dir %= 24;
		}
		else
			if (rotateFlag == 2) // Clockwise
			{
				Player.dir++;
				Player.dir %= 24;
			}
	}
}

Because the game loop syncs to the vertical fly-back, the time between two successive calls of this would be about 16.666 milliseconds. (=1000/60), but the check to see if 40 ticks have passed slows it down to 25 x 15 = 375 degrees rotation per second, i.e. just over one complete revolution which is more manageable than 900/360 = 2.5 full rotations. Plus if you wish rotation speed to be faster just change the 40 to a lower value.

This measured time delay is used quite a few times in the game. You could use it as a means to make the game get harder by having shorter delays on say aliens moving or firing.

Added the sources of another game

Added the sources of another game

Basic Computer games bookThis was a text mode game, my idea being to do something like the old Star Trek BASIC game but better. I called it Star Empires and it’s on GitHub, just follow the link to GitHub on the C Games sources link.

The zip file includes both C and a C++ version. Both will compile with Visual C++ 2019 Community edition. There is a minor compile error, a = that should be == in the C++ source. I ill get round to fixing it and uploading a replacement.

I do get a bit of pleasure (more like an exercise in masochism!) converting old BASIC games to C. I’m looking at the two Creative Computing books (and while 95% of the games are not exactly great (well lets be generous and say they were good 45 years ago!) but there’s one or two that might be worth the effort! I bought these in 1982 lost those and then bought them a few years back again.

Plus when you think how the games industry has matured since the late 70s and 80s, and many of those early programmers will have cut their teeth on games like that before learning more advanced stuff, so  lets not be too harsh!

 

A Game engine in C – permafrost

A Game engine in C – permafrost

Permafrost imageIt just shows what you can do in 38,000 lines of code. Permafrost Engine is an OpenGL 3.3 Real Time Strategy game engine written in C.  The image is from the game Everglory.

You need SDL 2 plus a few other dependencies listed on the site to build the engine.  It’s also cross-platform.

I’ve added it as a permanent link to the C Code links.

Browsing the source code of old and commercial games

Browsing the source code of old and commercial games

 

Archive photos
Image by Pexels from Pixabay

This page on a website called WikiZero has a long and very extensive list of games whose source code is available. That doesn’t always mean you can build the game. Many games are very old and in BASIC or assembly (.g. Elite is available in various forms).

It might have been created for a different platform or more likely the source code is available but the graphics and sound assets aren’t, unless you have bought the game, perhaps from sites like gog.com and so have them.

One thing to be aware of, many of the links on WikiZero go to the excellent wayback machine which is part of archive.org. This is under threat by some commercial publishers because they have lent ebooks during the Covid lockdown period without any limitation.  So if you are interested in anything I suggest you check it out sooner rather than later, just in case.

For instance here is the C source code for a TRS-80 game from 1979 called Paravia. It looks like a much expanded version of the Classic Computer game Hammurabi.  Note the wayback machine can take a few seconds to retrieve a webpage. They have a very large chunk of the web’s websites in there…

Progress on the Match Three game

Progress on the Match Three game

Match Three game Having a week off work has let me work on this game a bit more. I’ve put in about eight hours and it is now correctly dropping.

I’d never programmed one of these before so my first version used a board of pieces plus a secondary array for holding “transitions”. A transition was a struct that held information about two pieces being swapped and the current coordinates of each piece.  It seemed to be quite messy code and was quite buggy with pieces on top of other pieces.

So I then switched to a system where each board cell had a pointer to a struct for a piece (held in an array).  If the piece wasn’t moving the program calculated its pixel coordinates from the board coordinates and drew it there. If it was moving, it would no longer have board coordinates and would use the pixel coordinates to draw it.

That was better but then I thought why not just have the board just be a 2D array of structs with one struct for each piece.

This is the struct for each piece.

 

struct Cell {
	int piece;
	int moving;
	int scEndX, scEndY;
	float scCurrentX, scCurrentY;
	float velY, velX;
	int bdEndX;
	int bdEndY;
	int angle;
	int lock;  //1 = locked. Display padlock
	int size; // used when killing to diminish size
};

SDL2 does rotation very nicely; you don’t need to pre-render shapes just call SDL_RenderCopyEx instead of SDL_RenderCopy and specify the angle and one or two other parameters. When a piece is removed, it animates for about a half-second, rotating and shrinking in place. That’s the purpose of the angle and size fields.

If the lock value is 1 then the piece stays in place and won’t drop. You have to remove the lock by forming a line that includes the locked piece. When the line is removed, all locked pieces in the line remain but without the lock.

So far the game is currently about 800 lines of code. There’s no game level structure, high-score table, sounds, bonus pieces or even a basic piece matching algorithm. I’ve been testing by just randomly removing three vertical or horizontal pieces and then having unlocked pieces above fall down.

This 3rd version does not suffer from the Mexican-wave problem that the first and second version had. Sometimes when a column of pieces moved down, instead of all pieces moving together they moved one-by-one. New pieces get added in when the top row piece finishes dropping away.

So now on with the book and the next part of the game.

Working on the Match Three game

Working on the Match Three game

Match three gameThe second game is Match Three and I’d made some good progress. You can view some .mp4s from earlier this month here. The first one (MatchThree) shows rotations, something I’d never realised SDL is very good at doing. Graphics are from the excellent Dutch website (it’s in English) Kenney.nl.

The second mp4 (transitions) shows some animations. And the MatchThreeDropping shows pieces both being removed (first rotating and shrinking) and pieces dropping. However it also shows a flaw.  Sometimes all the pieces move together, other times (and this is the flaw) it shows them dropping one by one- Mexican wave-like, rather than all moving together.

My original algorithm, which I am now scrapping, had a transitions table. When the space or spaces below a piece became blank, a transition was created which had start and end positions. The piece was removed from the board (a simple 2d array) and reinstated in the board when it had finished moving to the end pixel position.

I think I have a much better method now, I still use a board but each element has a pointer to a piece in a big array of piece structs. I track both the coordinates in the board (0-9,0-9) and in pixels as each piece is 64 x 64. When a space is created in the board, all the pointers are shuffled and each piece is told to move from it’s old pixel position to its new one.

The move algorithm operates purely on the all pieces in the piece array not the board. The flawed algorithm worked on both the board and transition array and was quite messy. Sometimes you have to start with a clean slate than try and fix code that is working correctly.

Array vs pointer in C

Array vs pointer in C

Grid array
Image by Anja🤗#helpinghands #solidarity#stays healthy🙏 from Pixabay

A common pattern (I use the word loosely) in my C programs is to have an array of structs to hold things like asteroids and bullets in the game. There are two ways to process an array:

  1. As an array e.g. asteroids[index].
  2. As a pointer to an individual array element. Asteroid * pAsteroid = &(asteroids[index]); then refer to pAsteroid ->

One of the tents of software design though not that often said is that the easier the code is to read, the easier it is to understand. Programmers spend a lot of time reading code. Anything that lightens the cognitive load is good. I suspect it might also be faster, but not by a great deal.

Of course pointers make some programmers nervous. To me though they simplify the code. There is however another way to simplify the code. Use #define so you might have something like this:

#define table asteroids[index]

So everywhere you have a asteroids[index]., you put in table instead.
This for example from Chapter 36 DrawAsteroids()

	for (int i = 0; i<MAXASTEROIDS; i++) {
		if (asteroids[i].active) {
			numAsteroids++;                    // keep track of how many onscreen
			int sizeIndex = asteroids[i].size; // 0-3
			int asize = sizes[sizeIndex];      // asteroid size 280,140, 70,35
			target.h = asize;
			target.w = asize;
			asteroidRect.h = asize;
			asteroidRect.w = asize;
			asteroidRect.x = asize * asteroids[i].rotdir;
			target.x = (int)asteroids[i].x;
			target.y = (int)asteroids[i].y;

Would become

	for (int i = 0; i<MAXASTEROIDS; i++) {
		if (table.active) {
			numAsteroids++;                    // keep track of how many onscreen
			int sizeIndex = table.size; // 0-3
			int asize = sizes[sizeIndex];      // asteroid size 280,140, 70,35
			target.h = asize;
			target.w = asize;
			asteroidRect.h = asize;
			asteroidRect.w = asize;
			asteroidRect.x = asize * table.rotdir;
			target.x = (int)table.x;
			target.y = (int)table.y;

What do you think?

So I thought I’d try Code::Blocks

So I thought I’d try Code::Blocks

Code::blocks compiler options

Code::Blocks is an alternative cross-platform open source IDE for C/C++ (and Fortran!). It doesn’t include a compiler but can work with most of them.  It’s also written in C++ (you’d never guess from the name!) and so is fast.

Installing is just a

sudo apt install codeblocks

When you install it, it looks for installed compilers and gives you the choice of which is the default.

When you create a project there are a few types and one that got me excited was SDL. It creates a skeletal project and it was only when compiling that I realised it was for SDL1, not 2.  It’s the nature of open source that things take time to remedy. So don’t bother with it.

Anyway I copied in my source files and clang objected because it couldn’t find the SDL2 files. The fix isn’t too difficult. In Code::Blocks, navigate to Project Build Options then in Compiler settings > Other compiler options add these lines

-lSDL2

-lSDL2_image

-lSDL2_mixer

and in the Linker settings > Other linker options

-lSDL2

-lSDL2_image

-lSDL2_mixer

Note those are -l () not i or 1.

After that it compiled and linked ok. The compiled code is in the bin/Debug folder. However to get Asteroids to run you need to copy in the images, sounds, and masks folders and the highscore.txt file. After that it runs fine, but note when you compile it seems to delete everything in the folder.

So overall it wasn’t a difficult thing to do and I’m going to install it on a Raspberry Pi and see how that goes. I’ve already got Visual Studio Code installed on it and working but having a second IDE (both using the same compiler) is no bad thing.

Success with gamepad mappings

Success with gamepad mappings

SNES Gamepad
Image by Marco Sberveglieri from Pixabay

My ploy with running gamepad-tool on the Linux laptop worked and I was able to get the correct mappings to use in my game. Though weirdly it seems to have X and Y buttons mixed up as well as A and B.

In the end I hard-coded the mapping string and set it up with this code:

	if (SDL_GameControllerAddMapping("030000001008000001e5000010010000,NEXT SNES Controller2,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0")==-1){
		LogError("Unable to load gamepad mappings from gamepad.txt");
	}

Then in my ProcessEvents() function which handles I/O events, I added this code:

			case SDL_CONTROLLERBUTTONDOWN:
			if (event.cbutton.state== SDL_PRESSED){
				switch(event.cbutton.button){
					case SDL_CONTROLLER_BUTTON_A:
					    fireFlag =1;
					    break;
					case SDL_CONTROLLER_BUTTON_B:						
					    jumpFlag =1;
					    break;
					case SDL_CONTROLLER_BUTTON_X:
					    shieldFlag =1;
					    break;
					case SDL_CONTROLLER_BUTTON_Y:						
					    thrustFlag =1;
					    break;						
					case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
					    rotateFlag = 1;
					    break;
					case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
					    rotateFlag= 2;				
					    break;
					}
				}

There’s similar code for the SDL_CONTROLLERBUTTONUP except it checks for the state = SDL_RELEASED and in the switch statement it sets each flag to 0. So inspite of the code, it’s the Y button that does shields and the X button does thrust, B button fires and A button does the hyper space jump.

My Orange Pi – self resurrected

My Orange Pi – self resurrected

USB JoypadBack in November 2018, I was in Nottingham and passed a stand at the Winter Fayre. It was offering a console with 18,000 games on it for about £70. I bought one and what I got was an Orange PI with a 16 GB SD Card (all but full) and two USB joypads.

The game software used the Retro-Pie software, but the games were a massively illegal collection of games (for about ten different consoles including CBM-64, SNES, ZX Spectrum) put together by the company that supplied these “consoles”. Amazingly I found four games on there that I had written back in the 80s in this collection.

It was a bit of an odd PI. Instead of powering up through the power slot, it came with a USB to 5V connector. Looking about on the web I found it is this model in a nice acrylic case. Anyway, after three months it stopped working and it was pushed in to a drawer where it remained until today. I tried it today and it came back to life, I suspect the mains-to-USB adaptor is broken but as I’ve a drawer full of them it’s not a problem.

The reason for mentioning this is not the Orange Pi, nor the games but the joypads. I had a look on the libSDL website and I hadn’t realised that there was quite extensive support built in to SDL.  So my next task is to add game controller support for the asteroids game.