
- •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

Diverting the Game Flow – State Stack
We can look at a state as an independent screen in the gaming software, an object that encapsulates the logic and graphics of a determined group of functionality and information.
Nothing stops us from creating a state that behaves in any way we'd like; however, there are some usual guidelines into what belongs to the same state. Let's try to prove this shallowly by looking at the commercial games of our time. We will often see most games showing introduction videos, from the trailer of the game to
company brand logos. We can look at each of these screens as states. In fact, having a VideoState that would simply playback a video and proceed to the next state would fit this model perfectly!
Then, we usually see a title screen, which is all about fancy artwork and minor information. That would be another state. Usually, by pressing a key, we would enter into the main menu, which itself is another effective state. If we look closely at any game, we can more or less define what belongs to each state, and that is the exact point so you can understand the concept better. There are countless ways you can separate your game into multiple states, but practicing always makes you achieve cleaner and more efficient designs!
Using such a system is of extreme importance. The combination of all these screens working together as one final product always makes a game feel more professional and rich in features.
However, not all the states are the same. While some states take over the whole screen and are running individually, others will work together, in parallel, rendering to the same screen, to achieve a variety of effects such as the very common pause screen, which still shows the game in background without motion.
To manage states efficiently and in an easy way, we create the stack!
The state stack
One way to visualize the flow of the game screens would be to picture a finite state machine of all the screens and how they trigger each other's appearance. However, while that works and is logically accurate, we broaden the concept of the active state into a stack.
[ 114 ]
www.it-ebooks.info

Chapter 5
Finite State Machine (FSM): While this is a well known concept across the world of computation, we will shortly describe the state machine as a collection of states that ensures that only one state is active at any given time. The transition of the current state into a new one is always triggered by a condition or a timer. So, for any state of the FSM, there will be a determined set of triggers that will activate new states when appropriate.
Now, turning the active state into a stack essentially means that the current state is not an individual piece anymore, but rather a stacked group of pieces, when necessary. Usually, the state mechanism will only have one state active at a time,
and while this is true, we effectively have a finite state machine as it is known by the computer science community. In other situations, however, such as the infamous pause screen, we will break the concept of FSM a little and have states on top of states, representing the active state all together.
As you can see in the following figure, a usual game flow can be represented like this:
Begin |
Title Screen |
Pause Screen |
|
|
Game Screen |
|
|
Main Menu Screen |
|
|
End |
[ 115 ]
www.it-ebooks.info

Diverting the Game Flow – State Stack
To manage all these screens and transitions, we create the StateStack class:
class StateStack : private sf::NonCopyable
{
public:
enum Action
{
Push,
Pop,
Clear,
}; |
|
public: |
|
explicit |
StateStack(State::Context context); |
template <typename T> |
|
void |
registerState(States::ID stateID); |
void |
update(sf::Time dt); |
void |
draw(); |
void |
handleEvent(const sf::Event& event); |
void |
pushState(States::ID stateID); |
void |
popState(); |
void |
clearStates(); |
bool |
isEmpty() const; |
private: |
|
State::Ptr |
createState(States::ID stateID); |
void |
applyPendingChanges(); |
private:
struct PendingChange
{
...
Action action; States::ID stateID;
};
private:
std::vector<State::Ptr> mStack; std::vector<PendingChange> mPendingList; State::Context mContext; std::map<States::ID,
std::function<State::Ptr()>> mFactories;
};
[ 116 ]
www.it-ebooks.info

Chapter 5
We also create the so called State class:
class State
{
public:
typedef std::unique_ptr<State> Ptr; struct Context { ... };
public: |
|
|
State(StateStack& stack, Context context); |
virtual |
~State(); |
virtual void |
draw() = 0; |
virtual bool |
update(sf::Time dt) = 0; |
virtual bool |
handleEvent(const sf::Event& event) = 0; |
protected: |
|
void |
requestStackPush(States::ID stateID); |
void |
requestStackPop(); |
void |
requestStateClear(); |
Context |
getContext() const; |
private: |
|
StateStack* |
mStack; |
Context |
mContext; |
};
Adding states to StateStack
All states in the game have a unique identifier declared in an enum States, located in the StateIdentifiers.hpp file. For example, ID States::Game refers to the GameState class.
Initially, we register inside the stack all the states we may use. We do not create all the state objects from the beginning, since some of them may never exist, therefore we avoid loading resources of never-used states. Instead, we have factory functions that create a new state on-demand, represented by std::function. The member variable StateStack::mFactories maps state IDs to those factory functions.
[ 117 ]
www.it-ebooks.info