
- •Credits
- •Foreword
- •About the Authors
- •About the Reviewers
- •www.PacktPub.com
- •Table of Contents
- •Preface
- •Introducing SFML
- •Downloading and installation
- •A minimal example
- •A few notes on C++
- •Developing the first game
- •The Game class
- •Game loops and frames
- •Input over several frames
- •Vector algebra
- •Frame-independent movement
- •Fixed time steps
- •Other techniques related to frame rates
- •Displaying sprites on the screen
- •File paths and working directories
- •Real-time rendering
- •Adapting the code
- •Summary
- •Defining resources
- •Resources in SFML
- •Textures
- •Images
- •Fonts
- •Shaders
- •Sound buffers
- •Music
- •A typical use case
- •Graphics
- •Audio
- •Acquiring, releasing, and accessing resources
- •An automated approach
- •Finding an appropriate container
- •Loading from files
- •Accessing the textures
- •Error handling
- •Boolean return values
- •Throwing exceptions
- •Assertions
- •Generalizing the approach
- •Compatibility with sf::Music
- •A special case – sf::Shader
- •Summary
- •Entities
- •Aircraft
- •Alternative entity designs
- •Rendering the scene
- •Relative coordinates
- •SFML and transforms
- •Scene graphs
- •Scene nodes
- •Node insertion and removal
- •Making scene nodes drawable
- •Drawing entities
- •Connecting entities with resources
- •Aligning the origin
- •Scene layers
- •Updating the scene
- •One step back – absolute transforms
- •The view
- •Viewport
- •View optimizations
- •Resolution and aspect ratio
- •View scrolling
- •Zoom and rotation
- •Landscape rendering
- •SpriteNode
- •Landscape texture
- •Texture repeating
- •Composing our world
- •World initialization
- •Loading the textures
- •Building the scene
- •Update and draw
- •Integrating the Game class
- •Summary
- •Polling events
- •Window events
- •Joystick events
- •Keyboard events
- •Mouse events
- •Getting the input state in real time
- •Events and real-time input – when to use which
- •Delta movement from the mouse
- •Playing nice with your application neighborhood
- •A command-based communication system
- •Introducing commands
- •Receiver categories
- •Command execution
- •Command queues
- •Handling player input
- •Commands in a nutshell
- •Implementing the game logic
- •A general-purpose communication mechanism
- •Customizing key bindings
- •Why a player is not an entity
- •Summary
- •Defining a state
- •The state stack
- •Adding states to StateStack
- •Handling updates, input, and drawing
- •Input
- •Update
- •Draw
- •Delayed pop/push operations
- •The state context
- •Integrating the stack in the Application class
- •Navigating between states
- •Creating the game state
- •The title screen
- •Main menu
- •Pausing the game
- •The loading screen – sample
- •Progress bar
- •ParallelTask
- •Thread
- •Concurrency
- •Task implementation
- •Summary
- •The GUI hierarchy, the Java way
- •Updating the menu
- •The promised key bindings
- •Summary
- •Equipping the entities
- •Introducing hitpoints
- •Storing entity attributes in data tables
- •Displaying text
- •Creating enemies
- •Movement patterns
- •Spawning enemies
- •Adding projectiles
- •Firing bullets and missiles
- •Homing missiles
- •Picking up some goodies
- •Collision detection and response
- •Finding the collision pairs
- •Reacting to collisions
- •An outlook on optimizations
- •An interacting world
- •Cleaning everything up
- •Out of view, out of the world
- •The final update
- •Victory and defeat
- •Summary
- •Defining texture atlases
- •Adapting the game code
- •Low-level rendering
- •OpenGL and graphics cards
- •Understanding render targets
- •Texture mapping
- •Vertex arrays
- •Particle systems
- •Particles and particle types
- •Particle nodes
- •Emitter nodes
- •Affectors
- •Embedding particles in the world
- •Animated sprites
- •The Eagle has rolled!
- •Post effects and shaders
- •Fullscreen post effects
- •Shaders
- •The bloom effect
- •Summary
- •Music themes
- •Loading and playing
- •Use case – In-game themes
- •Sound effects
- •Loading, inserting, and playing
- •Removing sounds
- •Use case – GUI sounds
- •Sounds in 3D space
- •The listener
- •Attenuation factor and minimum distance
- •Positioning the listener
- •Playing spatial sounds
- •Use case – In-game sound effects
- •Summary
- •Playing multiplayer games
- •Interacting with sockets
- •Socket selectors
- •Custom protocols
- •Data transport
- •Network architectures
- •Peer-to-peer
- •Client-server architecture
- •Authoritative servers
- •Creating the structure for multiplayer
- •Working with the Server
- •Server thread
- •Server loop
- •Peers and aircraft
- •Hot Seat
- •Accepting new clients
- •Handling disconnections
- •Incoming packets
- •Studying our protocol
- •Understanding the ticks and updates
- •Synchronization issues
- •Taking a peek in the other end – the client
- •Client packets
- •Transmitting game actions via network nodes
- •The new pause state
- •Settings
- •The new Player class
- •Latency
- •Latency versus bandwidth
- •View scrolling compensation
- •Aircraft interpolation
- •Cheating prevention
- •Summary
- •Index

Chapter 5
Thread
A thread is essentially a function that runs in another branch of execution. You know the mandatory main() function, right? That is the entry point of every application, when it is called by the operating system, it creates one thread: the main one. You can visualize it as a sequential stream of commands that flows until the main() function is over and exits the program.
We can conclude from this that one thread is one function call. The same way main() is a thread function, there can be others. So, if inside the main function, we spawn a new thread by "calling" its function, the only difference between that and a normal call is that the program doesn't wait until that function ends, but rather continues execution while another stream of commands starts running in parallel.
This is the essence of multi-threading and there isn't a lot to add to it. To do this branching in execution, SFML provides sf::Thread. This class implies that you have to link a sf::Thread object to a function on its constructor, such as
sf::Thread(&myFunc) for a global function or sf::Thread(&MyClass::myFunc, myClassObject) for a member function of a class.
When you call sf::Thread::launch(), all it does is to call the linked function in a separate thread.
Once that function returns, the thread is also shut down automatically. Destroying the sf::Thread object while its thread is still running results in an abrupt termination of the thread.
Seems easy, right? Well, there are some more things to have in consideration. Using threads is very straightforward but there are concerns we must always have in mind when working with them.
Concurrency
When two threads are running in parallel, everything will go smoothly if they don't touch the same data at the same time. Anyway, it is very normal that two or more threads want to read/write to the same variables, if not for more, to communicate between them.
It probably goes without saying that if the processor is reading and writing to the same memory address at the same time, we are going to have a nice crash or an undefined behavior in our program, which can be troublesome to debug and correct.
But then, how to guarantee that multiple threads operate on shared data at turns, with proper synchronization? This is a very delicate topic that must not be taken lightly; however, there are mechanisms in SFML that help us achieve this!
[ 133 ]
www.it-ebooks.info

Diverting the Game Flow – State Stack
Here, we introduce you to sf::Mutex and sf::Lock. These are incredible tools to protect shared data when working with multi-threading. We won't be explaining in depth how they work internally, but rather try to apply it directly and understand it by example, by looking at the ParallelTask class implementation.
Task implementation
The code for this implementation is as follows:
class ParallelTask |
|
{ |
|
public: |
|
|
ParallelTask(); |
void |
execute(); |
bool |
isFinished(); |
float |
getCompletion(); |
private: |
|
void |
runTask(); |
private: |
|
sf::Thread |
mThread; |
bool |
mFinished; |
sf::Clock |
mElapsedTime; |
sf::Mutex |
mMutex; |
}; |
|
By taking a look at the ParallelTask declaration, you can see that the API used by LoadingState exposed. Besides that, you can see the runTask() function, which is the actual thread function that is launched in parallel execution.
Then, in its members, we can see the expected sf::Thread, the sf::Clock to count the elapsed time, and a Boolean variable to check if the task is done yet or not. The sf::Mutex object is meant to protect both the mClock and mFinished variables from concurrent access, as you will see in the following sample:
bool ParallelTask::isFinished()
{
sf::Lock lock(mMutex); return mFinished;
}
[ 134 ]
www.it-ebooks.info

Chapter 5
The first line in the function's body is what we call locking variables. If you noticed,
isFinished() is called by LoadingState::update(), which is the main thread while mFinished can be changed by the task thread as well, immediately when it finishes. This could randomly cause a simultaneous read and write by two threads, which would result in bad luck for us as programmers. We say randomly because there is nothing controlling the synchronization of the two threads, the simultaneous access can either happen or not.
By locking the sf::Mutex object before touching sensitive data, we ensure that if a thread tries to lock an already locked resource, it will wait until the other thread unlocks it. This creates synchronization between threads because they will wait in line to access shared data one at a time.
Because sf::Lock is a RAII compliant class, as soon as it goes out of scope and is destructed, the sf::Mutex object automatically unlocks.
To finalize, here is the actual thread function of our task:
void ParallelTask::runTask()
{
// Dummy task - stall 10 seconds bool ended = false;
while (!ended)
{
sf::Lock lock(mMutex); // Protect the clock
if (mElapsedTime.getElapsedTime().asSeconds() >= 10.f) ended = true;
}
{ // mFinished may be accessed from multiple threads, protect sf::Lock lock(mMutex);
mFinished = true;
}
}
You may have noticed that there is a lock in every read or write of the shared variables. The extra brackets are just a way of releasing that same lock as soon as possible, so the variable is then available for other threads to access.
All this function does is it remains in a while loop until the clock has ticked for ten seconds and then lets the thread finish after setting mFinished to true.
[ 135 ]
www.it-ebooks.info