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

Every Pixel Counts – Adding Visual Effects
Defining texture atlases
A texture atlas describes the concept of a single texture that contains multiple objects. You may also encounter other terms, such as sprite sheet, or tile set in the case of squared tiles put together. Texture atlases allow having fewer image files, which decreases the amount of switches between different textures at runtime. Since texture switching is a rather slow operation on the graphics card, using texture atlases may result in notable speedups. Till now, we used separate textures for each object: one for each aircraft, pick-up, projectile, button, and background. Every texture was stored in its own PNG file. The code design looked as follows:
•Textures were stored inside TextureHolder, our container storing sf::Texture objects.
•We had an enum Textures::ID to identify the different textures in a TextureHolder. By that, we could easily refer to different textures without knowing the actual sf::Texture object or the filename.
•The textures used in the scene were loaded in World::loadTextures().
•They were bound to sprites in the specific entity classes such as Aircraft. For a given entity, data tables stored the texture ID it used.
The SFML sprite class sf::Sprite offers the possibility to set a texture rectangle
(or texture rect for short), containing the pixel coordinates of a specific object inside the texture. You already came across this functionality when we implemented the tiling background for our world in Chapter 3, Forge of the Gods – Shaping Our World. The rectangle is of type sf::IntRect and stores four integral values: the x and
y coordinates of the left-upper pixel (members left and top) as well as the size (members width and height).
For example, the following texture rectangle rect begins at (0, 15) and has a width of 30 and height of 20. The size excludes the last pixel; the pixel with coordinates (30, 35) is outside the rectangle.
sf::IntRect rect(0, 15, 30, 20);
Given a texture and a rectangle, you can initialize a sprite using the constructor, or you can set the attributes later with the corresponding methods.
sf::Texture texture = ...; sf::IntRect rect = ...;
[ 186 ]
www.it-ebooks.info

Chapter 8
sf::Sprite sprite(texture, rect);
sf::Sprite sprite2; sprite2.setTexture(texture); sprite2.setTextureRect(rect);
If no rectangle is specified, the sprite will assume that the whole texture is used. This is what we have always done so far.
Adapting the game code
We need to extend a few parts of our code to work with texture rects instead of whole textures. First, we must remove many of our resource identifiers. All the aircraft, projectile and pickup textures will be merged to one texture, with an ID of Entities. The texture containing the three buttons is accessible via Buttons.
Eventually, we only have the following identifiers:
namespace Textures
{
enum ID
{
Entities,
Jungle,
TitleScreen,
Buttons,
Explosion,
Particle,
FinishLine,
};
}
In case you wonder, Jungle is the new background we will paint. It is much bigger and far more interesting than the desert we had before. FinishLine is a texture used to mark the end of the level, instead of the black void. It is embedded to the scene graph using SpriteNode. Explosion and Particle are going to be introduced soon.
[ 187 ]
www.it-ebooks.info

Every Pixel Counts – Adding Visual Effects
With the new image files in our Media folder, the method World::loadTextures() can be adapted accordingly. We also modify our data tables to store a texture rectangle in addition to the texture ID. The rectangle coordinates are hardcoded in the initialization functions.
struct AircraftData |
|
{ |
|
Textures::ID |
texture; |
sf::IntRect |
textureRect; |
... |
|
}; |
|
std::vector<AircraftData> initializeAircraftData()
{
std::vector<AircraftData> data(Aircraft::TypeCount);
data[Aircraft::Eagle].texture = Textures::Entities; data[Aircraft::Eagle].textureRect = sf::IntRect(0, 0, 48, 64);
...
return data;
}
The last part to extend is the entities that use the textures. Now, we initialize the sprite with both texture and texture rect:
namespace
{
const std::vector<AircraftData> Table = initializeAircraftData();
}
Aircraft::Aircraft(Type type, const TextureHolder& textures, const FontHolder& fonts)
: mSprite(
textures.get(Table[type].texture), // sf::Texture
Table[type].textureRect) |
// sf::IntRect |
, ... |
|
{ |
|
centerOrigin(mSprite); |
|
... |
|
} |
|
Analogous steps have been applied for textures other than the one for the Eagle aircraft. That's pretty much it; the new code should now directly work with texture atlases! Visually, there will be no difference to what we had before.
[ 188 ]
www.it-ebooks.info