Category: SDL

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.

Code::Blocks revisited

Code::Blocks revisited

Code::Blocks SDL2 demoSo after yesterday’s post I also installed Code::Blocks on Ubuntu 20.04 LTS, the recent six monthly Ubuntu release. Guess what, it’s a much newer version of Code::Blocks that looks slightly different and does include SDL2. Although the demo program it creates is C++ not C (That coloured bar picture is the demo).  I haven’t used it enough to see what’s different between this and version 16.01.

The version of Code::Blocks on the 18.04LTS Ubuntu  was 16.01 and on Ubuntu 20.04 LTS it’s Code::Blocks 20.03. I keep my Ubuntus up to date but the 18.04 LTS hasn’t switched to the newer Code::Blocks which surprised me. I’m guessing that the maintainers of the 18.04 LTS Ubuntu repositories just haven’t updated their copy of Code::Blocks.

One thing I hadn’t explored in Code::Blocks is the debugging and this seems a lot more powerful than what you get in Visual Studio Code.   This screenshot below from version 20 shows it is more akin to Visual Studio debugging rather than Visual Studio Code debugging what with CPU registers, stack, memory dump and threads.

Code::Blocks Debugging Menu

 

A new mini game console

A new mini game console

playdatePlaydate sounds a tad dodgy but is actually a small handheld game console with a 2.7-inch, 400 × 240 screen (173 ppi) and costing $149. It’s due out sometime this year.

The reason I mention it is it runs games written in C (or Lua).  It also comes with 12 games. No mention of what’s inside it (RAM, CPU) though that’s described as ‘beefy’ but it has Wi-Fi, Bluetooth, USB-C, and a headphone jack.

That thing sticking out of the right is a hand crank. No, not for charging the battery but as a game input device. If you create a side-scroller game you can have it scroll one way by cranking in one direction and reverse it by cranking in the other way. Well that’s certainly original!

There will be a development kit available for it and you will be able to write programs for it though at the moment that looks as if its only on a Mac which is a bit of a shame. Oh I have a Mac but I much prefer my Windows PC or Ubuntu.

Compared to the massive screen sizes available on PCs, 400 x 240 sounds a bit small screen size. If you remember the CBM-64 from the 80s, it is exactly the same size as that screen and there were some great games out for it.

I’m excited about this because I believe it could be a renaissance for C Game programming.

SDL. Surfaces or textures?

SDL. Surfaces or textures?

Screenshot from DominionsWhen I first started on the asteroids game, I did it as a set of tutorials on About.com. That was around 2011/2012 and back then I used SDL 1 which was all about surfaces not textures. When I picked up SDL coding again in 2018, it had progressed to SDL2 which uses textures.

As I understand it, a surface is a structure in RAM while a texture is a structure in VRAM ( the memory in the GPU(. That makes it much faster copying pixels from VRAM to VRAM than from RAM to VRAM.

But I found it much easier to read pixels from a surface than from a texture. Chapter 38 in my e-book has a mask utility. It loads the images from disk into a surface then reads the pixels and creates the masks from that. Masks are used in collision detection. I had previously thought you couldn’t read from a texture.

However after reading this article, which writes directly to the pixels in a texture, it makes me think that reading from them should be possible. I will give it a go just because I’ve not seen it done anywhere.

Picture is from the game Dominions, created with SDL.

Fun with Raspberry Pi 4

Fun with Raspberry Pi 4

Bugs!
Image by Ron van den Berg from Pixabay

So it turned up and I setup things up similar to the 3B+. My interest was in seeing what frame rate it can manage compared to the 27 FPS that the 3B+ managed.

When I eventually got Clang, VS Code etc. installed and setup, compiled etc. it crashed just like it did on the 3B+ when first run. And again it failed to load the am2.msk file; I will really have to figure out what’s going on there. But also it would now not load the a1.png image. This is the one with the 24 x 280 x 280 asteroid images.

SDL provides a function SDL_GetError so I added that to the output when an image file fails to load. The error message that came back was Texture dimensions are limited to 4096×4096. Now this is weird for this Pi has 4 GB of RAM (the 3B+ has 1GB) and is outputting on the same 24″ monitor that the 3B+ used as well. Now it’s true that the a1.png file has dimensions of 6,720 x 64, so I can understand why that would cause grief but not why it worked on the 3B+. I suspect it has to do with RAM being allocated between the GPU and CPU so I’ll check that out.

I also installed Clang-6.0 to try that. On the Pi, installing clang defaults to Clang-7 (they changed the name so it no longer has a .0 on the end!). The release notes for Clang-7 suggested a possibility to do with abi incompatibility between Clang-7 and earlier versions. Bit of a longshot but I thought, that might explain the fail to load am2.msk file but no joy.

Well there’s nothing like juicy tender bugs to get my teeth into… the battle is on.

Problems debugging SDL2 with Visual Studio Code

Problems debugging SDL2 with Visual Studio Code

500 numbers blitted to screen by SDL2So my demo program runs fine when I run it from the terminal. It creates a SDL Window and blits lots of numbers, but if I try to start it in the debugger, it gets to this function and fails in the SDL_CreateWindowAndRenderer.

void InitSetup() {
	srand((int)time(NULL));
	SDL_Init(SDL_INIT_EVERYTHING);
	SDL_CreateWindowAndRenderer(WIDTH, HEIGHT, SDL_WINDOW_SHOWN, &screen, &renderer);
	if (!screen) {
		LogError("InitSetup failed to create window");
	}
	SetCaption("Example Two");
	LoadTextures();
}

And in the Debug Console I can see two of these:

@”error: XDG_RUNTIME_DIR not set in the environment.\r\n”

followed by my error message InitSetup failed to create window.

I’ve looked online and there’s one or two mentions. Now possibly it might be because I’m running Ubuntu 18.04 LTS under Hyper-V Manager.  I’ll try this on a laptop where I’ve installed the same version of Ubuntu on and see if the same thing happens.

 

The mighty Blit

The mighty Blit

Showing an asteroid being targetted by the player's shipWhat makes possible all of the fast graphics in SDL2 is really one instruction.

SDL_RenderCopy – The link goes to the SDL Wiki.

This copies part of a texture into video RAM (aka VRAM). You must specify which texture is to be copied, a rectangle into the source and a rectangle into the destination VRAM.

So what is a Texture? In SDL2, it’s a structure that manages an area of VRAM. At the start of the game, image files are uploaded into Textures, the file bits are copied from disk and stored in an area in VRAM.

Every frame, a background image (another texture) is copied to the screen area. Then all moving objects are rendered into this area by calling SDL_RenderCopy for each object. The entire object (be it player ship, bullet or asteroid) is then rendered onto the screen area at the correct point. This is sometimes called blitting or more accurately bit blitting; blit is shorthand for bit block transfer.

A rectangle is just a struct holding four ints. The first two ints are the x and y positions and last two are width and height.  The player’s ship consists of a graphic 64 pixels high by 16 x 24 (=1,536) pixels wide. That’s 24 images, each rotated by 15 degrees from the previous one. So the source rectangle is always x = rotation (0-23) x 64, y = 0 and both height and width are 64. Remember, the source x,y is relative to the source texture which is 1536 wide by 64 high.

The ship rotations start with 0 facing up, so the ship on screen is at rotation 18 (Facing Left) , so  x = 1152.

To make sure rendering is a smooth process and there is no tearing of the images, the screen VRAM is always off-screen when the objects are rendered into it. Then after all objects have been rendered (a posh word meaning copy!), the display is toggled so that the bank of VRAM that was off-screen is now on-screen i.e. visible and the other bank is now off-screen.

Objects are always rendered into off-screen VRAM and the flipping is done by a call to this SDL routine.

SDL_RenderPresent

When you create the renderer, you can specify whether SDL_RenderPresent is synced to the video card vertical refresh signal. If it is, then the display will only render 60 frames per second. If you don’t sync then you can have frame rates up to several thousand times per second. I once achieved 5,000 fps, because there was very little processing going on.  However your video card probably doesn’t refresh any faster than 60 fps so it’s a bit pointless!

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.