Book Image

SFML Game Development By Example

By : Raimondas Pupius
Book Image

SFML Game Development By Example

By: Raimondas Pupius

Overview of this book

Simple and Fast Multimedia Library (SFML) is a simple interface comprising five modules, namely, the audio, graphics, network, system, and window modules, which help to develop cross-platform media applications. By utilizing the SFML library, you are provided with the ability to craft games quickly and easily, without going through an extensive learning curve. This effectively serves as a confidence booster, as well as a way to delve into the game development process itself, before having to worry about more advanced topics such as “rendering pipelines” or “shaders.” With just an investment of moderate C++ knowledge, this book will guide you all the way through the journey of game development. The book starts by building a clone of the classical snake game where you will learn how to open a window and render a basic sprite, write well-structured code to implement the design of the game, and use the AABB bounding box collision concept. The next game is a simple platformer with enemies, obstacles and a few different stages. Here, we will be creating states that will provide custom application flow and explore the most common yet often overlooked design patterns used in game development. Last but not the least, we will create a small RPG game where we will be using common game design patterns, multiple GUI. elements, advanced graphical features, and sounds and music features. We will also be implementing networking features that will allow other players to join and play together. By the end of the book, you will be an expert in using the SFML library to its full potential.
Table of Contents (21 chapters)
SFML Game Development By Example
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Drawing images in SFML


In order to draw an image on screen, we need to become familiar with two classes: sf::Texture and sf::Sprite. A texture is essentially just an image that lives on the graphics card for the purpose of making it fast to draw. Any given picture on your hard drive can be turned into a texture by loading it:

sf::Texture texture;
if(!texture.loadFromFile("filename.png"){
    // Handle an error.
}

The loadFromFile method returns a Boolean value, which serves as a simple way of handling loading errors, such as the file not being found. If you have a console window open along with your SFML window, you will notice some information being printed out in case the texture loading did fail:

Failed to load image "filename.png". Reason : Unable to open file

Tip

Unless a full path is specified in the loadFromFile method, it will be interpreted as relative to the working directory. It's important to note that while the working directory is usually the same as the executable's when launching it by itself, compiling and running your application in an IDE (Microsoft Visual Studio in our case) will often set it to the project directory instead of the debug or release folders. Make sure to put the resources you're trying to load in the same directory where your .vcxproj project file is located if you've provided a relative path.

It's also possible to load your textures from memory, custom input streams, or sf::Image utility classes, which help store and manipulate image data as raw pixels, which will be covered more broadly in later chapters.

What is a sprite?

A sprite, much like the sf::Shape derivatives we've worked with so far, is a sf::Drawable object, which in this case represents a sf::Texture and also supports a list of transformations, both physical and graphical. Think of it as a simple rectangle with a texture applied to it:

sf::Sprite provides the means of rendering a texture, or a part of it, on screen, as well as means of transforming it, which makes the sprite dependent on the use of textures. Since sf::Texture isn't a lightweight object, sf::Sprite comes in for performance reasons to use the pixel data of a texture it's bound to, which means that as long as a sprite is using the texture it's bound to, the texture has to be alive in memory and can only be de-allocated once it's no longer being used. After we have our texture set up, it's really easy to set up the sprite and draw it:

sf::Sprite sprite(texture);
...
window.draw(sprite);

It's optional to pass the texture by reference to the sprite constructor. The texture it's bound to can be changed at any time by using the setTexture method:

sprite.setTexture(texture);

Since sf::Sprite, just like sf::Shape, inherits from sf::Transformable, we have access to the same methods of manipulating and obtaining origin, position, scale, and rotation.

It's time to apply all the knowledge we've gained so far and write a basic application that utilizes it:

void main(int argc, char** argv[]){
  sf::RenderWindow window(sf::VideoMode(640,480),
    "Bouncing mushroom.");

  sf::Texture mushroomTexture;
  mushroomTexture.loadFromFile("Mushroom.png");
  sf::Sprite mushroom(mushroomTexture);
  sf::Vector2u size = mushroomTexture.getSize();
  mushroom.setOrigin(size.x / 2, size.y / 2);
  sf::Vector2f increment(0.4f, 0.4f);

  while(window.isOpen()){
    sf::Event event;
    while(window.pollEvent(event)){
      if(event.type == sf::Event::Closed){
        window.close();
      }
    }

    if((mushroom.getPosition().x + (size.x / 2) >
      window.getSize().x && increment.x > 0) ||
      (mushroom.getPosition().x - (size.x / 2) < 0 &&
      increment.x < 0))
    {
        // Reverse the direction on X axis.
        increment.x = -increment.x;
    }

    if((mushroom.getPosition().y + (size.y / 2) >
      window.getSize().y && increment.y > 0) ||
      (mushroom.getPosition().y - (size.y / 2) < 0 &&
      increment.y < 0))
    {
         // Reverse the direction on Y axis.
        increment.y = -increment.y;
    }

    mushroom.setPosition(mushroom.getPosition() + increment);

    window.clear(sf::Color(16,16,16,255)); // Dark gray.
    window.draw(mushroom); // Drawing our sprite.
    window.display();
  }
}

The code above will produce a sprite bouncing around the window, reversing in direction every time it hits the window boundaries. Error checking for loading the texture is omitted in this case in order to keep the code shorter. The two if statements after the event handling portion in the main loop are responsible for checking the current position of our sprite and updating the direction of the increment value represented by a plus or minus sign, since you can only go towards the positive or negative end on a single axis. Remember that the origin of a shape by default is its top-left corner, as shown here:

Because of this, we must either compensate for the entire width and height of a shape when checking if it's out-of-bounds on the bottom or the right side, or make sure its origin is in the middle. In this case, we do the latter and either add or subtract half of the texture's size from the mushroom's position to check if it is still within our desired space. If it's not, simply invert the sign of the increment float vector on the axis that is outside the screen and voila! We have bouncing!

For extra credit, feel free to play around with the sf::Sprite's setColor method, which can be used to tint a sprite with a desired color, as well as make it transparent, by adjusting the fourth argument of the sf::Color type, which corresponds to the alpha channel:

mushroom.setColor(sf::Color(255, 0, 0, 255)); // Red tint.