Learn C Games

Learn C Games

Learn C Games Programming Book coverThis blog is about C and Games programming (in C mainly). There are now two ebooks written by David Bolton, author of the Learn C Games Programming for beginners EBook. This is the Windows version, with a Raspberry Pi/Linux one now out.  

The first 20 chapters introduce and teach C programming with many examples. This link is to an .mp4 of the asteroids game from the book. It’s about 90 seconds long and demonstrates all of the features of the game. High score table, rotating asteroids (four sizes), sound, explosions, ship hyper-jump and shields.

The remaining 30 chapters (20 in the Linux/Raspberry PI) builds up to full source code, about 2,000 lines, in 13 stages and I explain how each feature works and is implemented.  All of the book’s source code is on Github. (Windows) or (Linux). More about me. Buy the Windows one on Amazon(UK), Amazon(US) or the Linux/Raspberry PI. (UK). You can buy the book in other regions by changing the region in Amazon to your local one. 

 

Great mystery #1 solved!

Great mystery #1 solved!

It was kind of silly. I installed Debian 13 in hyper-V, just to see how different it is from Ubuntu.  Like Ubuntu, it starts in a default size. I looked in the settings and there was a Displays there so I tried it and got the screen resized to full screen size.

So I then went back to Ubuntu and tried that, and it worked. I believe that what helped was having guest services ticked in the Hyper-v settings.

Hyper-V settings Display settings in Ubuntu

Great mysteries – number 1

Great mysteries – number 1

Hyper-v that refuses to become fullscreen!I run Ubuntu in a hyper-V session.  It works very well and handy for getting screenshots. I’ve been using a 24.04 LTS for a while and decided I needed another one to test CyberPanel. i already have Webmin on my main one so wanted a clean Ubuntu so as not to mess Webmin.  It took ten minutes to setup then another 20 minutes to install 300+ updates.

Then I edited Grub to give me a fullscreen- 1920 x 1080.  You just edit /etc/default/grub with an editor run under sudo. I use Gedit but nano will do. Just change the line to this:

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash video=hyperv_fb:1920x1080"

followed by

sudo update-grub

and that should be it. Only it didn’t work in my new Ubuntu 24.04 LTS VM. I installed ifconfig from net-tools, connected to it from my Windows PC and copied grub across. I did the same with my older 24.04 LTS VM and compared the two grub files. Both identical yet one works fullscreen and the newer one doesn’t. Any ideas?

Don’t get Flutter and Dart mixed up

Don’t get Flutter and Dart mixed up

A bird a Flutter and Darts

I’m working on a game with a Flutter web client and two Dart terminal programs hence the visual pun. Annoyingly, you can’t compile a Dart exe for Linux on a Windows PC. You can do that in C# but I prefer to use Dart.

I have all the classes in two files (one is called classes.dart) and because I’m using JSON to persist game data, I use the build_runner package from pub.dev. Just add this before any classes:

@JsonSerializable()

Make sure if you have enums that every enum value has

@JsonValue('houses')

before it and add functions like this for each class you want to persist; in this case a Location class:

factory Location.fromJson(Map<String, dynamic> json) =>
    _$LocationFromJson(json);

Map<String, dynamic> toJson() => _$LocationToJson(this);

Then when it’s all done, do this to generate a file that handles loading and saving the specified classes.

dart run build_runner build

Along the way though I managed to get Flutter into a Dart program. I’m using SQLite but only in Dart, not in the Flutter app. Unfortunately I used the kIsWeb constant to exclude some calls (when the classes are used by the Flutter app) in my classes file.  But you can’t do that in a pure Dart program, it will not compile. Instead I wrote my own function.

bool isWeb() {
  return !Platform.isWindows && !Platform.isLinux;
}

Interestingly, the definition of kIsWeb in the API is this below, so it might be worth trying that out.

const bool kIsWeb = bool.fromEnvironment(‘dart.library.js_util’);

Ever do a sudo apt update on your Raspberry Pi?

Ever do a sudo apt update on your Raspberry Pi?

sudo apt update error message

 

 

 

 

And you get this error message?  It says

E: Release file for http://archive.raspberrypi.com/debian/dists/bookworm/InRelease is not valid yet 
(invalid for another 10h 37min 50s). Updates for this repository will not be applied.
E: Release file for http://deb.debian.org/debian/dists/bookworm-updates/InRelease is not valid yet 
(invalid for another 12h 15min 47s). Updates for this repository will not be applied.

If you do

sudo hwclock -s

It will fix it. Apparently it’s to do with the hardware clock having drifted and I’m guessing this causes an error condition. Still, its an easy fix!

 

Setting up SDL3 on Linux

Setting up SDL3 on Linux

SDL3 program running on Raspberry Pi.

I knew it wasn’t going to be easy, but it turned out to be quite a bit more difficult than I thought.

The problem is, unlike SDL2, there are no dev versions of SDL3 etc. yet, so you have to build it from scratch.

I’ll be honest, I’m not sure I could have done it without this GitHub repository. User Ravbug who is very busy person (752 contributions on GitHub in the last year- I tip my hat to him or her!) who provided that repository.

It sets up SDL3, SDL_image, sdl_mixer and SDL_ttf.

Follow his link to the Wiki page Scroll down to the bottom for the Linux instructions. I can confirm that it works on Raspberry Pi as well.  You’ll need to install cmake first with

sudo apt install cmake

Then run his cmake to build everything and go for a coffee.
Now go into the build folder under sdl3-sample and do

make

That only takes a second or so.

After you’ve done that you’ll end up with a load of files including an executable sdl-min that you can run. That’s what generated the Tiger’s head – it plays The Sting film’s theme (The Entertainer) music as well demonstrating that it’s using SDL_mixer as well as SDL3 and SDL_ttf (I’m guessing) and of course SDL_image.

But that is just the start

To use SDL3 etc in your C program, you need a bit more configuration than with SDL2. I’m in uncharted waters here but used an AI- Claude 4 to help me get through and it did.

The problem is you have to tell VS Code where the header files are located, the .so files and also the executable needs to know at runtime.

I set up Ravbug’s sdl3_sample in my home folder so all paths start /home/david/sdl3-sample. 

This is my tasks.json

 

{
    "version": "2.0.0",
    "tasks": [
        {
            "type": "shell",
            "label": "clang-14.0 build active file",
            "command": "/usr/bin/clang-14",
            "args": [
                "-I/home/david/sdl3-sample/SDL/include",
                "-I/home/david/sdl3-sample/SDL_image/include", 
                "-I/home/david/sdl3-sample/SDL_mixer/include",
                "-I/home/david/sdl3-sample/SDL_ttf/include",
                "-g",
                "${file}","${workspaceFolder}/hr_time.c",
                "-L/home/david/sdl3-sample/build",	
                "-Wl,-rpath,/home/david/sdl3-sample/build",				
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}",
                "-lSDL3",
                "-lSDL3_image", 
                "-lSDL3_ttf"   

            ],
            "options": {
                "cwd": "/usr/bin"
            },
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

The lines that are SDL3 specific include the -I’s to provide the include path. -L the path to the .so files and the -rpath line is the path to the runtime files which gets linked into the executable.

If you add these three lines into c_cpp_properties.json then you’ll also avoid the dreaded red squiggles.

            "includePath": [
                "${workspaceFolder}/**",
                "/home/david/sdl3-sample/SDL/include",
                "/home/david/sdl3-sample/SDL_image/include",
                "/home/david/sdl3-sample/SDL_ttf/include"
            ],

And your C’s #includes need the files prefixed like this :

#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#include <SDL3_ttf/SDL_ttf.h>

And here it is running on my Pi.

Missile Command running on a Raspberry Pi 5 with SDL3

Converting from SDL2 to SDL3 on Windows

Converting from SDL2 to SDL3 on Windows

Missile Command running with SDL3

These notes were made when converting an existing C game that used SDL2 to SDL3 on Windows. The game was originally developed for Linux Format and I had got it running on Windows with SDL2.

Windows include paths have been made consistent with Linux. The include files path for SDL3 need to be SDL3\… when setting them up. For SDL2, I had them in a folder c:\SDL2\include but noted that in SDL2.h include files were like this:

#include "SDL_main.h"
#include "SDL_stdinc.h"

While in SDL3’s SDL.h they are

#include <SDL3/SDL_stdinc.h>
#include <SDL3/SDL_assert.h>

So I put them c:\SDL3\SDL3

When you include them in your software they are like this:

#include <SDL3/SDL.h>
#include <SDL3/SDL_image.h>

Which is how they are in Linux.

The rest of these notes are taken from the differences between the SDL2 and SDL3 versions of the game. They are not complete but intended to give you an idea of some of the changes you may need to do.

SDL_TTF

TTF_RenderUTF8_Blended( is now TTF_RenderText_Blended with an extra text length parameter.

SDL_Rects are mostly replaced by SDL_FRect

This is a big change. Everywhere I was passing in an SDL_Rect became an SDL_Frect which is four floats rather than four ints.

SDL_RenderCopy is now SDL_RenderTexture and the last two params are now SDL_FRects.

To fix this I used a load of (float) casts.

SDL_RenderDrawLine becomes SDL_RenderLine and has an SDL_FRect parameter instaed of SDL_Rect.

Same for SDL_RenderDrawPoint which becomes SDL_RenderPoint.

SDL_GetMouseState keeps the same name but returns float * for both parameters now.

Setup changes slightly

There’s no SDL_SetMainReady() and SDL2main.lib is gone.

Also gone is SDL_INIT_EVERYTHING in SDL_Init()– you have to or the specific subunits. E.g. SDL_INIT_VIDEO | SDL_INIT_EVENTS

Also there’s no SDL_RENDERER_PRESENTVSYNC for SDL_CreateRenderer. Vsync is disabled by default as I found when my game ran about 30x faster and finished in a few seconds! Instead you need to call SDL_SetRenderVSync(renderer, 1) where 1 is syncing with each retrace, or 2 with every 2nd retrace.

Several of the events have been renamed, so SDL_KEYDOWN becomes SDL_EVENT_KEY_DOWN, SDL_MOUSEBUTTONDOWN becomes  SDL_EVENT_MOUSE_BUTTON_DOWN and similar for other events.  Also event.key.keysym.sym becomes event.key.key.

Finally SDL_FreeSurface( becomes SDL_DestroySurface.

I’m sure there are more but changing these was sufficent to get my game compiling and running correctly with SDL3.

Chapter list for my recent eBook

Chapter list for my recent eBook

Book cover for learn C games programming

The files on GitHub have been revised and now include all image and sound files and tasks.json updated for clang-14. Note because GitHub doesn’t allow hidden files/folders like .vscode to be uploaded, I’ve included the .vscode folders as vscode and you need to rename them.

Chapter 1. Introduction to C programming
Chapter 2. Setting up a development environment
Chapter 3. Writing your first C program
Chapter 4. Working with Variables and Data Types
Chapter 5. So what is a pointer?
Chapter 6. A little Bit of C code
Chapter 7. A Quick Overview of Visual Studio
Chapter 8. Array variables
Chapter 9. Loop the loops
Chapter 10. More loops

Chapter 11. About operators
Chapter 12. Structs
Chapter 13. Functions
Chapter 14. More about functions
Chapter 15. Pointers
Chapter 16. Text Strings
Chapter 17. The Asteroids Game
Chapter 18. Architecture of C Programs
Chapter 19. Graphics
Chapter 20. An SDL Demo program

Chapter 21. The Game Loop
Chapter 22. Drawing Text
Chapter 23. More Game Elements
Chapter 24. Adding in asteroids
Chapter 25. Adding in bullets
Chapter 26. Editing with Visual Studio Code
Chapter 27. Restructuring
Chapter 28. Show the Score
Chapter 29. Explosions
Chapter 30. Sounds

Chapter 31. Detecting Collisions Part 1
Chapter 32. Detecting Collisions Part 2
Chapter 33. Detecting Collisions Part 3
Chapter 34. Passing Parameters into functions
Chapter 35. Detecting Collisions Part 4
Chapter 36. Ever Wondered about if (!value)
Chapter 37. Adding Level Structure
Chapter 38. Alien Ships!
Chapter 39. The High Score
Chapter 40. Finishing off

Debugging C/C++ and Rust with codelldb

Debugging C/C++ and Rust with codelldb

Extensions for C/C++As a user of Visual Studio since about VS 5, I’ve become accustomed to being able to debug. With VS Code, it’s also been easy but now that I program in C and Rust, the codelldb extension makes things very easy. You need other extensions: for Rust- the Rust Analyzer extension and for C/C++ the Microsoft C/C++ extension.

And for debugging for both the codelldb extension which is shown.  It uses the usual Microsoft debugging keys: F5 to start F10 to step over, F11 to step into and F9 to toggle a breakpoint.

Below is an example of debugging a Rust program.

debugging Rust program in VS Code

Rust on Windows – problem with sdl2.lib

Rust on Windows – problem with sdl2.lib

I’m currently unable to compile Rust programs that use SDL2 on Windows. No problems on Ubuntu or Raspberry Pi OS, just Windows 11.
Compiling an SDL2 app (in Rust) on WindowsAlthough it says cannot open input file SDL2.lib, I think the problem is a parameter passed into Link.exe.

The text from the image above is listed below- I’ve broken it to make it readable as it’s displayed preformatted and unmodified it is all on a single very wide line!

 = note: "C:\\Program Files\\Microsoft Visual Studio\22\\Community\\VC\\Tools\\MSVC\.43.34808\\bin\\HostX64\\x64\\link.exe" 
"/NOLOGO" "C:\\Users\\dhbol\\AppData\\Local\\Temp\\rustcA1PhoK\\symbols.o" "<70 object files omitted>" 
"D:\\development\\rustapps\\choice\\target\\debug\\deps/{libsdl2-f8d94d30d19bed49.rlib,libsdl2_sys-325e30d8e9547ff4.rlib,
libbitflags-d15393d08e2f31fc.rlib,liblazy_static-c28c0e13093a4168.rlib,liblibc-851e0bf801239f69.rlib}.rlib" 
"<sysroot>\\lib\\rustlib\\x86_64-pc-windows-msvc\\lib/{libstd-*,libpanic_unwind-*,libwindows_targets-*,
librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libunwind-*,libcfg_if-*,liballoc-*,
librustc_std_workspace_core-*,libcore-*,libcompiler_builtins-*}.rlib" "SDL2.lib" "SDL2_image.lib" "SDL2_ttf.lib" 
"legacy_stdio_definitions.lib" "kernel32.lib" "kernel32.lib" "advapi32.lib" "ntdll.lib" "userenv.lib" "ws2_32.lib" 
"dbghelp.lib" "/defaultlib:msvcrt" "/NXCOMPAT" "/OUT:D:\\development\\rustapps\\choice\\target\\debug\\deps\\choice.exe" 
"/OPT:REF,NOICF" "/DEBUG" "/PDBALTPATH:%_PDB%" "/NATVIS:<sysroot>\\lib\\rustlib\\etc\\intrinsic.natvis" 
"/NATVIS:<sysroot>\\lib\\rustlib\\etc\\liballoc.natvis" "/NATVIS:<sysroot>\\lib\\rustlib\\etc\\libcore.natvis" 
"/NATVIS:<sysroot>\\lib\\rustlib\\etc\\libstd.natvis"
= note: some arguments are omitted. use `--verbose` to show all linker arguments
= note: LINK : fatal error LNK1181: cannot open input file 'SDL2.lib'␍

But if you try running part of it like the first line
“C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.43.34808\\bin\\HostX64\\x64\\link.exe”
“/NOLOGO” “C:\\Users\\dhbol\\AppData\\Local\\Temp\\rustcA1PhoK\\symbols.o”

Well the path to link..exe is correct, but there’s no  rustcA1PhoK\symbols.o in that temp folder. Any suggestions welcomed…

I just solved it.

I’ve left this in, in case anyone else has this problem.

You need to add an environment variable LIB with the address of the SDL .lib files including ttf, image and mixer. Make sure they’re all in this folder:

C:\Users\dhbol\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib

The bold part of the path will be different on you PC.

In File Explorer, right-click on This PC then click Properties on the popup menu.

File Explorer - This PC,.

 

 

 

It’ll open Settings – About, and you need to click Advanced system settings.

settings_about

This opens System Properties and on that you click Environment variables.

System properties on Windows

Environment variables popup on Windows

 

 

 

 

 

 

 

 

Now just click New and add Lib and that path It should look something like mine. Now reopen Visual Studio and your SDL2 Rust app should now build and run.