- •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 3
Zoom and rotation
The sf::View utility gives us another two precious features: zooming and rotating our view.
We can use the sf::View::zoom(float factor) function to easily approach or move away from the center of the view. The factor parameter means that the current view's rectangle will be multiplied by it. It is really that simple. A factor of one will have no effects on the zoom function. A factor bigger than one will grow the view's rectangle, which makes objects appear smaller and gives us the impression to watch from a more distant point of view. The opposite applies when using a factor less than one, which will make the world appear to be closer, just like when we zoom in a real camera.
About rotation, sf::View allows us to turn our view orientation to another angle than the default one, zero, in degrees. The easiest way to visualize the results of this operation is to picture how our world is seen under the default view orientation, and then imagine the whole content rotating relative to the center of the view.
This is a concept that is better understood by experimenting until the desired effect is reached. You can use sf::View::rotate(float degrees) to add a rotation angle
to the current one, or sf::View::setRotation(float degrees) to set the rotation of the view to an absolute value.
Landscape rendering
As you can observe in the C++ sample for this chapter, our aircraft travels continuously over a desert. This continuity can be achieved in many ways and with many different levels of detail and complexity. However, we chose to go in a very simple and yet effective way of doing it, using a feature that SFML provides out of the box.
SpriteNode
In order to display our background sprite through the scene graph, we created a new SceneNode type, the SpriteNode, which acts as a simple sf::Sprite that can be plugged into our tree structure. Conveniently, this is all we need to make our landscape. We only have to create SpriteNode and attach it to our background layer of the scene graph.
[ 71 ]
www.it-ebooks.info
Forge of the Gods – Shaping Our World
To demonstrate the implementation of a new node type, there follows a small snippet of the SpriteNode declaration:
class SpriteNode : public SceneNode
{
public: |
|
|
explicit |
SpriteNode(const sf::Texture& |
texture); |
|
SpriteNode(const sf::Texture& |
texture, |
|
const sf::IntRect& |
rect); |
private: |
|
|
virtual void |
drawCurrent(sf::RenderTarget& |
target, |
sf::RenderStates states) const;
private:
sf::Sprite mSprite;
};
The sf::Sprite class is constructed and prepared at startup and not touched again in the future. This is a proof of the scene graph's power, showing us that the relative transforms work very well because we can manipulate the positioning, rotation, and scale of SpriteNode, and these transforms are inherently applied to the sf::Sprite object as well.
With the sprite node, we have also introduced the last piece in our scene graph for the moment. The following diagram should give you an impression of the current inheritance hierarchy. The grey classes at the top are part of SFML, the black ones are ours.
sf::Drawable sf::Transformable sf::NonCopyable
SceneNode
SpriteNode |
|
Entity |
|
|
|
|
|
|
|
|
|
Aircraft
[ 72 ]
www.it-ebooks.info
Chapter 3
Landscape texture
In order to have a good landscape, without wasting too much memory having multiple images to represent it along the whole level, we used a tileable texture.
A tileable texture is no more than an image that can be put together continuously, without letting the player notice that we actually have one single image repeating itself. This is possible because the seam between every two instances of the image is not noticeable. The image's beginning fits perfectly into its ending, creating an illusion of infinity, with just one texture. As you can see in the following figure, multiple desert images can be put together without creating a hard seam, giving the illusion that it's only one image.
That is exactly what we did. We made a desert "tile", which is only big enough to fill one screen. Using the following technique, we made it look infinite, repeating itself along the whole level.
Texture repeating
The key to our tiling effect is exactly the texture repeating feature that SFML provides us. Every sf::Texture comes along with the option to enable repeating along both axis with the sf::Texture::setRepeated(bool) function.
When repeating is enabled for a texture, it means that it will be theoretically infinite, tiling itself continuously as much as required. When a sf::Sprite object links to
a texture in this mode, it will behave normally until the sprite requests a texture rectangle that is larger than the texture's real dimensions. In that moment, the sprite will display the texture along its whole size.
[ 73 ]
www.it-ebooks.info