Thursday, 15 May 2025

[SFML & C++] 7 - Animating Sprites // Tutorial

This is part of a series of small projects and tutorials using C++ and SFML

Library version: SFML 3.0.0
C++ Standard: ISO C++20

In this project, we'll make a simple app that loads a texture (image), gives that texture to a sprite and animates it. We'll also create a custom animated sprite class that inherits from sf::Sprite, that you can use for other projects. Here's what the finished product will look like:

How To SFML Animate Sprites Tutorial using C++ - Basic Beginner


Step 1 - Creating a Sprite

What is a sprite? In game development it usually refers to a drawable object that references a texture. They usually have functions that allow you to set the position, rotation, scale and others. They are used primarily for the main "objects" in your games like the main character, enemies, items etc. 

By themselves, sprites have no concept of animation. They load a single image each frame. Therefore to animate them, you need some code that updates the image each frame.

Why doesn't SFML do this for you? Well, animations come in all shapes, sizes and varieties. The speed, duration, loop ability. These are all left down to the programmer to implement as the developers of the libraries cannot be expected to cater to every situation.

Enough talking though. Let's make a sprite and show it on the screen. Sprites load textures. So we'll need a texture first and give a reference of it to the Sprite.

I'll be using the following spritesheet for the purposes of this tutorial:

Please note this is for learning purposes only.

The reason I'm using it is because all the separate frames we need are nicely laid out into little squares so we can easily access them from our texture when we need to update the animation each frame.




Step 2 - Offsetting into a Texture

Now this doesn't work as expected because we're just loading the entire image and displaying that. We only want to display part of the texture. So we'll need to create an offset into it. I've already done some calculations for you and those squares are 48x48 pixels. The start of the walk animation is at x268, y576.



That's better.

Step 3 - Animating the Frames

So to animate this, all we have to do is move the texture rect 48 pixels to the right (+ a 4 pixel gap between frames) to give us the next frame. Then we do the same again, then go backwards to the start. We can simulate this by just using a vector to store the positions.



How To SFML Animate Sprites Tutorial using C++ - Basic Beginner

And done! And that's how you basically animate sprites. We use the delta time to gives us a nice animation speed as well. Animation is a massive part of game development and it would be nice if we could wrap up of our animating code into something reusable.

Wednesday, 14 May 2025

[Dev Diary] The Tool Jam 5 - Creating a Random Lore Generator + Fun with Markov Chains

It's about time I took part in a game jam but this one really intrigued me. I think it's because I tend to work on the developer tools these days rather than the game itself; I find it more interesting. Therefore, this game jam caught my eye.

I've always been fascinated with random generators. The kind from the early internet days like Seventh Sanctum. I've long wondered how these worked and I've created some simple generators using the basic idea over on my playground using HTML, CSS and *shudder* JavaScript. I thought this would be the perfect jam though to do some research and really dig into how random generators used to be made convincingly and do it using my favourite C++ and SFML combo.

Warning, this is a long post.

Research - Ask ChatGPT
First off, I had a great conversation with ChatGPT about how those sorts of generators were made and what kind of algorithms they used. It started off explaining 3 ways to implement my game jam idea:

Grammar-based using rules and templates
Basically recursive string placement and you supply a whole load of word types.
The [adjective] [noun] of [proper-noun or abstract-concept]

Mad-libs approach
A more basic version of the grammar based approach, where different types of sentences are supplied.
Long ago, in the time of the #adjective# #noun#, the #faction# waged war against the #enemy#

Layered Abstraction
Basically structured nonsense. Here, the word types are already built up from other approaches to create something that sounds more AI generated.
[Proper Noun] was last wielded by the [Faction], a cult that believes [Purpose].

I found this really interesting, especially as the word types like [adjective] and [Purpose] could easily equate to an enum. I could create a list of enum word types, store everything in text documents and then "build" sentences from these word types. Add in some logic using rules and templates, like adjectives must always be before a noun, and I could quickly create something quite random.

Markov Chains
I then asked if all this data was really just stored in text files and it said yes, but ChatGPT always says yes. But in its explanation it started talking about Markov Chains. This is the kind of computer science mumbo jumbo I was hoping to get from GPT. I went off and researched Markov Chains and it turns out they are basically a way to generate sequences of stuff. You seed them, and the next item in the sequence is based off the item before it but they don't have full context over the entire sequence. Kind of like ChatGPT itself. 

Markov Chains are statistical mimicry. They have no concept of grammar templates or meaning. In essence you could say they are the spiritual ancestor of LLM's. 

Armed with this knowledge, I then started wondering if you could give Markov Chains more context. ChatGPT informed me that my best bet would be to implement Conditional Markov Chains mixed with Probabilistic Grammar and Weights. This involves different Markov models like religiousMarkov or plantMarkov mixed with assigned weighted probabilities. So if a weapon name is "Cursed", you're more likely to get a backstory involving betrayal or a wielder with a tragic fate over a backstory where the goddess bestowed it due to kindness.

V1 - Basic C++ Lore Generator
Armed with some fun research, I then went off and made a basic console version of what I wanted. To start off I made a simple enum of word types, created a map of word types to strings. Then 'built' sentences using those word types and created a random sentence by filling in the word type with one of those strings:


All good stuff. 

V2 - Basic C++ Lore Generator
I expanded slightly on this version and moved over to using text files so I could easily get GPT to generate a load of words or phrases for me that I could add to the files. I added a way to load those in to be used instead of hardcoding it in main.


V3 - Creating a Basic Markov Chain Model
This is where shit got fun. With the help of ChatGPT, I got a very simple Markov generator going that takes in a text file of words and then "trains" itself on that data set. Then, in the place where it gets a random word from the "word pool" of that specific type, it would request a word from the generator instead. These words were actually plausible and looked 'right'.

You can see here my full list of names I created and the name the generator created. I also cleaned up the code at this point and moved everything out into seperate classes as it was getting messy in main and I hate having global variables and static classes just hanging around.

At this point, it kind of felt like I had created baby's first LLM and I was very happy. It then occurred to me that I could then chain the markov chains together to create the initial lore template itself, essentially creating a fully generative 'lore engine' so to speak.

I put this to ChatGPT and it started talking about word tokens instead of using individual characters and it was like a lightbulb went off in my head. ChatGPT itself works on tokens instead of characters (you've probably seen this from the infamous 'how many r's are there in strawberry'). I would now be recreating this, albeit in a very basic and crude manner.


V4 - Markov Based Word Chain Generator

First, I turned my initial Markov generator class into a pure virtual class, and created MarkovWordGenerator which inherited from it. The Markov Word Chain generator still needs an order and train/generate functions but they need to be slightly different. This would then allow me to have Word generators and Sentence Generators.

This did work...somewhat. The markov model was too accurate given my limited data set I was feeding it. This meant that it always returned the exact sentence as found in the training text file. Giving it an order of 1, gave the model less context but the sentences produced lacked context and so the sentences were jumbled and didn't make sense (in English anyway).

I also wanted more control over the types of sentences created. So I ended up making a text file that had sentence templates for item lore.

I then "trained" a markov model on a large text file that ChatGPT produced for me of item lore sentences. Then created functions that allow the user to just call "generateItemLore()", and it goes off, chooses a random item lore template, then replaces the bracketed sections with something from a word pool or in the case of {{sentence}}, replaces it with a markov-generated sentence.

I then added a way to have the user input a name for the item or generate one randomly:
Creating a random Lore Generator using pure C++ and Markov Chains

Even with a larger "data set", I still have to set the model to the lowest setting (1). The sentences make more sense than previously but can still seem 'off'. It'll do though.


V5 - Creating the UI

Now with a simple item lore generator pretty much created, I wanted to move away from the console for a bit. I kept them as separate projects so I could continue working in the console one to prove out ideas then move it over to the UI version.

So I created a window, added a nice background image and some background music, then I got to creating the text boxes and remembered that SFML and text is not great. This is a program that is mainly reliant on entering text and displaying text. So I switched out SFML for FLTK. FLTK is a fantastic little library that is way more suited for this kind of task than SFML. The only issue is that I have my own wrapper around the library and I haven't turned that into a library yet so I had to pull every single file across.

Honestly, the thought of having to create a scrolling text box class in SFML just had me noping out within 5 seconds. FLTK was made for this kind of program.

The weekend then happened. Also it was sunny, which is rare for england, so I forgot about it until an hour before the jam closed. I considered not submitting but for once I was seeing a jam through. And I managed to submit with 11 minutes left to go:


Overall Thoughts
This was a lot of fun. Especially as I've come to understand how LLMs were initially created. There's is so much power in having a "locally trained" generator though. I'd be interested in making this do other things like generate documentation on code bases. But for the moment, I'd like to add a proper UI using a library and then expand it to creating lore for places and people. Also, allow more modding capabilities.


Thursday, 8 May 2025

[SFML & C++] 6 - Displaying User Input/Simon Says // Tutorial

This is part of a series of small projects and tutorials using C++ and SFML

Library version: SFML 3.0.0
C++ Standard: ISO C++20

In this project, we'll make a simple app that generates a random string of keys the user needs to press. The user will have 5 seconds to input the keys in that order. Here's what the finished product will look like:

How To SFML Display Get User Input Simon Says Tutorial using C++ - Basic Beginner


Step 1 - Getting User Input

So we won't add the timing aspect in just yet. We'll start by creating some code to generate keys that the user needs to input. For simplicity, there will be 8 keys the computer can choose from: W A S D, and 8426 (the arrow keys if you have a number pad, if you don't have a number pad, choose keys that make sense to you).

The reason I'm not using the actual arrow keys is because they aren't considered text, they're key events, that's why I'm using the number pad.

First though, lets add a way to display what users type:



We do the usual things of creating a font and a text object to display our characters. Then we capture text entered and add it to a stream. We need to cast those events to chars otherwise it'll just display numbers.

Step 2 - Generating Keys To Press

Now, these keys for our "game" will never change (at least for this program, you may want to expand on it). So I'm going to push them back into a vector at the start of the program.


I won't be bothering with capitals in this program, but that's something you can add if you like.

Now we need to create a function that will generate our random combo and a function that will generate random numbers for us, as std::rand() isn't all that random.


Now let's display the combo to the user. I also moved the user input text object down the screen slightly, so the computer's combo is at the top.




With that done, we can move onto adding some logic to see if the combo is correct or not.

Step 3 - Checking For a Correct Combo

We can generate random combo moves and the user can give input, let's add a way to check if the input and the combo move matches and do something with that information.

Let's compare the strings when the user presses enter:


We check for the Key Release event as that is a one time event. Key Presses can happen over multiple frames depending on how fast you are. Because we check for a key release, we need to capture the 'key press' event of the enter key, otherwise it's character will be appended to our stream (which we don't want as that will mess up our combo check). Also, please excuse the magic number here. 13 is the unicode value for enter in SFML.


Step 4 - Adding A Time Limit

So to add some extra spice to our "game". Let's add in a time limit. The user has to correctly enter the combo in say 5 seconds. We'll start by adding a countdown timer to the screen. This is basically our Stopwatch but in reverse.




Now we need to use the clock and delta time to start the countdown.


Don't forget to reset the timer if enter is pressed as well:

And that's pretty much it!

How To SFML Display Get User Input Simon Says Tutorial using C++ - Basic Beginner

For the most part this is a fully functioning program. However our code is starting to get a bit "unmanageable" in the amount of places we need to keep track of what to update in text boxes and reset timers. We should really have win and loss scenarios now handling that in one place so the game is easier to modify and expand.

Exercise
Add a scoring system. Refactor to check for appropriate "win" or "lose" scenarios.

Tuesday, 6 May 2025

[SFML & C++] 5 - Stopwatch // Tutorial

This is part of a series of small projects and tutorials using C++ and SFML

Library version: SFML 3.0.0
C++ Standard: ISO C++20

In this project, we'll make a simple app that tracks time from when we push a start and stop button. We'll use knowledge gained from the real-time clock project and the mouse tracker. Here's what the finished product will look like:

How To SFML Stopwatch Timer Tutorial using C++ - Basic Beginner


Step 1 - Displaying Seconds Passed

We need to start off by creating the text object to store the time:




Now, let's make it increase every second. First we need something to store the elapsed time in.


Now we just need to update the elapsed time each frame, calculating the minutes, seconds, milliseconds, and then format them into our preferred string format. Unlike the real-time clock tutorial, I don't want this only updating every second as I want to see the milliseconds updating.


Using the elapsedTime variable, I calculate how much time has passed since the program started. asMilliseconds() returns a 4 digit int, I wanted to display it as 2 digits so I mod by 1000 and then divide by 10. The reasoning for this is, if the total time was say 1 minute, 23 seconds and 456 milliseconds
  • elapsedTime.asMilliseconds() would be 83,456
  • 83,456 % 1000 gives 456 (just the millisecond portion)
  • 456 / 10 gives 45 (showing only the first two digits)
std::setfill() and std::setw() are stream manipulations that control how data is formatted when output to a stream. They're very handy. Setfill() fills characters to whatever you specify (so here it's 0). Setw() sets the width of the field to the number of characters you specify. If a value takes up fewer characters, it will be padded with the fill character from setfill().

They're repeated because steam manipulators only affect the next output operation, they don't persist across multiple insertions to the stream.

Step 2 - Creating a Stop/Start Button

We now have a way of tracking how much time has passed since the program started. But that's not how stopwatches usually work. They start at 0 until you start them, so we need a button to make that happen.

There isn't a button class in SFML. The creators of the library leave those types of implementations up to the developer so they can create their own custom classes. In this tutorial, we'll make something simple that acts like a button using sf::RectangleShape.



The button doesn't do much right now and it doesn't have any text in it. Let's create another text object and render that with the button.




You might've noticed creating text objects is quite repetitive. Again, SFML doesn't abstract further from this though to give us developers freedom to create our own complex classes. At this point you could see how useful a RectangleButton class would be and the kind of things you'd need to do to create that...

Render order is also important in any 3D application. The first object you draw will be the first item that's drawn, allowing you to "draw on top" of other items. This is often referred to as the "z order".


Step 3 - Adding the Stop/Start Logic

Now we've got a button, let's do something when we press it. We know from our Mouse Tracker project that we can get the co-ordinates of the mouse, what if those co-ordinates just so happened to be where our button is and we press the left mouse button? This is basically how we check for our button presses.

Let's add a check for if LMB is pressed:

With this done, let's have a think about the logic. The app should start with a zeroed timer and only start when we press the button. If the button is pressed again, the timer stops. Press it again, it starts and continues from where it left off. This sounds like we'll need a bool to keep track of whether or not the stopwatch is running.



If you run the app now, nothing happens. Good. So let's flip that bool if LMB is pressed:


If you run the program now:
How To SFML Stopwatch Timer Tutorial using C++ - Basic Beginner

And that's pretty much a stopwatch at this point. It would be nice if it had a reset button though.

Exercise
Implement a reset button.

If you get stuck: Exercise Solutions. There are many ways to do this; this is just one way of doing it.

Friday, 2 May 2025

[SFML & C++] 4 - Mouse Tracker // Tutorial

This is part of a series of small projects and tutorials using C++ and SFML

Library version: SFML 3.0.0
C++ Standard: ISO C++20

In this project, we'll make a simple app that tracks the mouse movement on the screen and prints the X and Y coordinates. Here's what the finished product will look like:

How To SFML Mouse Tracking (Checking inside window) Tutorial using C++ - Basic Beginner


Step 1 - Displaying Text

So first, we need to display some text to the screen. We can do that using SF::Text.

In SFML, you need to create a font as well that you can pass to the text object, otherwise you won't be able to display anything. So let's do that as well:




Step 2 - Getting The Mouse Coordinates

Next we need to get the mouse coordinates. This is something we can do in our update section.


If you run the program now, the coordinates will update depending on where the mouse is, relative to the top left-hand corner of the window.

Your mouse can go outside of the window though and it will still report where it is on the screen. Depending on the type of app you're building, you may want to allow the mouse to go outside the screen, or you may want the window to have full focus of the mouse.

As I'm a games developer, usually the mouse should stay inside the window, so I'm going to do that.



Here I used a function on the main window itself to "lock" the mouse inside the window, whilst the window has focus. I find this to be quite annoying as I like to use most things in windowed mode, but to each their own. Grabbing the mouse may cause some issues if you have a 3D camera as the mouse may need to "go outside" the window in order to rotate the camera properly.

In the update section, I modified the code slightly to check if the window has focus, so we only display the coordinates when it does. 

Another slightly different way to do this is use some events:



Here I created a bool to track if the mouse was in the window. I then used the events sent by the library to set that bool and used that instead of checking if the window has focus. This is an approach I prefer, however it really depends on the application. Sometimes you really don't want the mouse leaving the window.

You can read more about these classes here: