When 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.
This is in C, but applies to C++ as well and is part of stdlib. Perhaps you’ve written a program and when it exits, you want it run some final code. The typical use case for this is releasing resources such as memory allocations and closing files. If you are doing networking then it might also be closing network handles.
Then you need atexit(). You pass in the name of void function. When it finishes, it jumps to that function and runs it. Here’s some code to show it in use.
void ExitFunction(void) {
printf("Exited");
}
int atv = atexit(ExitFunction);
As good programming practice, you should check that value to make sure it’s 0. If it isn’t then your exit handler failed to register. I’m not sure what would cause that (overzealous antivirus software?)
You might notice that the ExitFunction has a (void) parameter rather than (). The two are the same but atexit() has been told to expect void parameters and will be disappointed should you fail to comply. Not disappointed enough to give you an error but you will incur a warning and you know how I hate to see those.
The reason why I hate warnings is that not all warnings are equal. This one is trivial and could be ignored, but others aren’t and really need dealing with. So I go for zero tolerance to warnings. Some compilers like gcc have a setting to tell the compiler to treat all warnings as errors.
The very first program I wrote in any programming language was sometime in October 1976. It was in BASIC and it had this line or something very similar. Even then I was into random numbers. I know, uppercase!
LET DIEROLL = RANDOM(6)+1
I’ve been writing small utility that I’ll publish in a few days. It’s 100% in C and I decided instead of using srand(time(null)) for generating random numbers, I’d use something with a bit more oomph. That something is a library called sodium. Using it for just generating random numbers is a bit overkill. But it has the benefit that the random numbers are good enough random to be used in cryptographic code. Not all random number generators are good enough. This one is.
And it’s easy enough and adds just one dll, or you can compile it statically. I’ll do that once I figure it exactly which Visual Studio settings to change.
It takes just one include –
#include <sodium.h>
Then one call to initialise it.
int i = sodium_init();
if (i<0 ) {
error("Unable to initialise sodium library. Error = ",inttoa(i) );
}
After that you can call one of several functions. Here’s an example from my code. It fills a 64 byte key with the numbers 0-63 but shuffled like cards.
typedef char key[64];
key _key;
uint32_t ival;
int i,index1,index2;
for (i = 0; i < 63; i++) {
_key[i] = i;
}
for (i = 0; i < 1000; i++) {
do {
index1 = randombytes_uniform(64);
index2 = randombytes_uniform(64);
} while (index1 == index2);
ival = _key[index2]; // swap two indices
_key[index2] = _key[index1];
_key[index1] = ival;
}
The do loop (how often do you actually see those used in code!) generates two indexes in the range 0-63, making sure that they are not the same. It then swaps the two values at those indexes, and does this 1,000 times. It’s very similar to card deck shuffling code.
Do you know how long it would take you to work through all the combinations of 64 numbers this way? IF you could do a million a second, it would take you 1.27×1083 seconds or 4.02×1075 years! Or to make it more meaningful it’s this large! 4.02,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000. That’s approaching (but still far far off) the time for the heat death of the universe which is estimated at 10100!
This site on Github has lots of interesting projects that will help you improve your C programming ability.
Whether it’s a chess engine, a sudoku solver, space invaders clone, tic-tac-toe (noughts and crosses for us Brits!), Othello, program a text adventure plus a lot of non games stuff as well.
Or do you fancy learning how to write your own virtual Machine in C? Authors Justin Meiners and Ryan Pendleton have crafted a 14 part tutorial that will teach you how to write a VM that can run assembly language programs.
You can’t return anything from a constructor. One way is to use exceptions but those can bring their own issues. Google’s C++ guidelines actually stipulate no exceptions and I’ve heard it from others as well that they prefer not to use them. Some people avoid it by having a mostly empty constructor and then an init() method to do the real initialisation and return a success/fail state.
But there is a simple trick that you can use, just return the state as a reference. Here’s an example. If you want to return more values, use a struct.
I’d read about enum class in C++. It’s a slight strengthening of the compiler checking compared to plain old enums. Why you may wonder? Well,
Conventional enums can implicitly convert to int, causing errors when someone does not want an enumeration to act as an integer.
Conventional enums export their enumerators to the surrounding scope, causing name space pollution.
The underlying type of an enum cannot be specified, causing confusion, compatibility problems, and makes forward declaration impossible.
Additionally you can declare the underlying storage type, which lets the compiler catch bugs where a value is too large for the storage. Here’s a made up example to show this:
As always bugs are the fault of the creator and mea culpa (my bad!). I can trace this back to my conversion from the Windows source to the Ubuntu version. This line in LoadMask
int numread = fread_s(mask, sizeofmask, sizeofmask, 1, fmask);
Became this line in the Ubuntu version.
int numread = fread(mask, sizeofmask, sizeofmask, fmask);
But should have been this instead.
int numread = fread(mask, sizeofmask, 1, fmask);
It affected numread and failed just on the masks/am2.msk load.
The other bug only applies on Raspberry Pi 4 and is a limitation of the implementation of SDL2 texture size.
One of the asteroids graphics is 6720 x 280 and the error it returns is Textures can’t be bigger than 4096×4096.
What is odd that it works on a Raspberry Pi 3B+ but not on the 4 which has 4 GB of RAM. Anyway I’m writing a program to transform the graphics from 24 x 1 shapes to 12 x 2. So the 280 x 280 shape file will be 3360 x 560. This will affect the player ship and all asteroids and need a slight change to the DrawPlayerShip() and DrawAsteroids() functions.
My secret: is I use a piece of software called Jutoh from a Scottish software house. It costs £35 and if you are writing a book or e-book I highly recommend it.
Note I have no connection with them except as a very satisfied customer.
It’s all the little things, inserting pictures, tables, handling source code that make it particularly good for non-fiction books.
It also includes formatting for various programming languages and is cross-platform with versions for Linux, Mac and Windows.
The current version of the Linux e-book has 55144 words, (307407 characters). It takes about 10 seconds to compile that into a .mobi (Amazon) or .epub file with all sorts of warnings.
Originally I started writing the first e-book in a text editor then imported it to MS-Word. But Word is not exactly great software for publishing non-fiction as it’s not desktop publishing. Actually you don’t need desktop publishing per se because Kindle reflows the text, but having pictures, source code and tables makes it more complicated.
I looked about, found Jutoh and consider myself very fortunate; it makes life much easier. I’ve also had excellent support from Jutoh’s creator Dr. Julian Smart who is also well known as a creator of wxWidgets.
Writing an e-book is a multi-pass project that takes me roughly 3-4 months part-time.
Pass 1. Develop the software and e-book structure i.e. chapters.
Pass 2. Write the chapters.
Pass 3. Look for typos. For now this is just me, but eventually I hope to be able to afford a technical editor.
Pass 4. Tidy up the layout. This is probably the slowest phase. Because of the images, tables and shortish code listings, it might look neat and tidy at one size, but if you change the viewing font size, it looks er not quite so neat! I can’t see any way round that.
A friend drew the original book cover but I’ve decided to pay for the cover for the Linux version.
If you have a bit of nesting and you want to make sure your braces match up, Visual Studio code (VSC) can help you with that.
Just drag the cursor over the left or right brace and it will highlight the corresponding brace. In the screenshot you can see the brace on the 2nd line and 5th lines are highlighted.
Here’s a second trick. You can quite easily collapse code blocks. On the left below is uncollapsed code. Now move the cursor between 3 and typedef and a down arrow should appear. Click it and it will collapse the block. It now shows a right arrow and you click it to expand it back.
That is, I have completed every one of the 13 stages in the game’s development and each is up and running on Ubuntu. It turned out easier than I thought though I still need to fix one or two things.
Because Clang doesn’t support the MSVC fopen_s, I did a quick fix and removed the error checking and when it first ran, it did another segmentation fault because the high score table file didn’t exist. D’oh!
That’s fixed now. Crashing because a file is missing is a very bad practice! Also for some reason last night, Windows and Ubuntu fell out and copy/paste between them wasn’t working. It is working today. I’ve noticed this can be a little bit sensitive at times and I think it was the Windows side that fell over.
However I’ve also been playing with Ubuntu 19.10 and Copy/Paste appears to be disabled on that. That kind of thing I find extremely irritating. I have Guest services ticked, so why does nothing I do enable it? 18.04 LTS apart from last night’s glitch is perfectly happy. And 20.04 Focal Fossa (I know!) is due out on April 23rd. It’s not quite ready but you can try it an early version if you like. I will be upgrading.