Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

11. August 2016

 

SFML, the Simple Fast Multimedia Library, just released version 2.4.0.  As it’s name suggests SFML is a cross platform media framework written in C++ most often used to make 2D games.  I actually have a pair of tutorial series ( SFML 2.x here || SFML 1.6 here ) if you are interested in learning more.

 

This release brings several changes and fixed.  From the release notes:

General
  • Added deprecation macro (#969)
  • Fixed issues reported by Coverity Scan static analysis (#1064)
  • Fixed some initialization issues reported by Cppcheck (#1008)
  • Changed comment chars in FindSFML.cmake to # (#1090)
  • Fixed some typos (#1098, #993, #1099, #956, #963, #979)
  • Updated/fixed string comparisons in Config.cmake (#1102)
  • Added the missing -s postfix for the RelWithDebInfo config (#1014)
  • [Android] Fixed current Android compilation issues (#1116, #1111, #1079)
  • [OS X] Update Xcode template material (#976, #968)
  • [Windows] Added support for VS 2015 (#972)
  • [Windows] Create and install PDB debug symbols alongside binaries (#1037)
Deprecated API
  • sf::RenderWindow::capture(): Use a sf::Texture and its sf::Texture::update(const Window&) function and copy its contents into an sf::Image instead.
  • sf::Shader::setParameter(): Use setUniform() instead.
  • sf::Text::getColor(): There is now fill and outline colors instead of a single global color. Use getFillColor() or getOutlineColor() instead.
  • sf::Text::setColor(): There is now fill and outline colors instead of a single global color. Use setFillColor() or setOutlineColor() instead.
  • sf::LinesStrip: Use LineStrip instead.
  • sf::TrianglesFan: Use TriangleFan instead.
  • sf::TrianglesStrip: Use TriangleStrip instead.
System
Features
  • [Android] Added sf::getNativeActivity() (#1005, #680)
Bugfixes
  • Added missing include in String.hpp (#1069, #1068)
  • Fixed encoding of UTF-16 (#997)
  • [Android] Fixed crash when trying to load a non-existing font file (#1058)
Window
Features
  • Added ability to grab cursor (#614, #394, #1107)
  • Added Multi-GPU preference (#869, #867)
  • Added support for sRGB capable framebuffers (#981, #175)
  • [Linux, Windows] Improved OpenGL context creation (#884)
  • [Linux, Windows] Added support for pbuffers on Windows and Unix (#885, #434)
Bugfixes
  • Updated platform-specific handle documentation (#961)
  • [Android] Accept touch events from "multiple" devices (#954, #953)
  • [Android] Copy the selected EGL context's settings to SFML (#1039)
  • [Linux] Fixed modifiers causing sf::Keyboard::Unknown being returned (#1022, #1012)
  • [OS X] Improved memory management on OS X (#962, #790)
  • [OS X] Fixed crash when resizing a window to a zero-height/width size (#986, #984)
  • [OS X] Use the mouse button constant instead of 0 to avoid a compiler error on OSX (#1035)
  • [OS X] OS X improvement: warnings + bugfix + refactoring, the lot! (#1042)
Graphics
Features
  • Added support for outlined text (#840)
  • Add support for geometry shaders (#886, #428)
  • Feature/blend mode reverse subtract (#945, #944)
  • Implemented support for mipmap generation (#973, #498, #123)
  • Added new API to set shader uniforms (#983, #538)
  • Rewrite RenderWindow::capture (#1001)
Bugfixes
  • Exporting some Glsl utility functions due to linking issues (#1044, #1046)
  • Fixed missing initialisation of Font::m_stroker (#1059)
  • Changed primitive types to be grammatically correct (#1095, #939)
Audio
Features
  • Implemented stereo audio recording (#1010)
Bugfixes
  • Added an assignment operator to SoundSource (#864)
  • [OS X] Updates OpenAL-soft for OS X to version 1.17.2 (#1057, #900, #1000)
  • Fixed a bug where vorbis can't handle large buffers (#1067)
  • Added support for 24-bit .wav files (#958, #955)
  • Fixed threading issue in sf::SoundRecorder (#1011)
  • Made WAV file reader no longer assume that data chunk goes till end of file to prevent reading trailing metadata as samples (#1018)
  • Fixed seeking in multi channel FLAC files (#1041, #1040)
Network
Features
  • Added optional argument on which address to bind (socket). (#850, #678)
Bugfixes
  • Fixed FTP directory listing blocking forever (#1086, #1025)

 

SFML is available for download here.

GameDev News

5. November 2015

 

In this tutorial we are going to look at playing back music in our SFML game.  We will look at streaming an ogg file from disk.  We will also quickly look at the basics of handling time in SFML as we add fast forward and rewind abilities to our music playback.

 

There is an HD version of this tutorial here.

 

Playing music files is different from playing audio files and we will deal with this in a separate tutorial.  Music files are designed to be streamed from disk, not resident in memory.  SFML supports the following file formats:

  • ogg
  • wav
  • flac
  • aiff
  • au
  • raw
  • paf
  • svx
  • nist
  • voc
  • ircam
  • w64
  • mat4
  • mat5
  • pvf
  • htk
  • sds
  • avr
  • sd2
  • caf
  • wve
  • mpc2k
  • rf64

 

You will notice a very noticeable exception from that list, the mp3 format. That is because the mp3 format is encumbered by a number of patents and should be avoided to protect yourself from potential licensing fees.  Fortunately the ogg format offers similar file sizes and similar audio quality as the mp3 format without the licensing pitfalls.  If you require to covert formats the free software Audacity is an excellent and easy choice.

 

The major difference between sound effect and music is the sound effect stays resident in memory, while a Music file is streamed from disk.  Both classes still possess a great deal of common behaviour.  In fact if you look at the inheritance tree you will see that they have a common base class.

 

image

 

Now lets finally create some code showing how to actually play and control music files.

 

// Demonstrate that the hills are alive with the sound of music
#include "SFML/Graphics.hpp"
#include "SFML/Audio.hpp"
#include <iostream>

int main(int argc, char ** argv){
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Demo Game");

  sf::Event event;
  sf::Music music;
  music.openFromFile("audio/goats_typicalamerican.ogg");
  music.setVolume(50);

  music.play();

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


      if (event.type == sf::Event::EventType::KeyPressed){

        // Up and down to control volume
        if (event.key.code == sf::Keyboard::Key::Down)
          music.setVolume(music.getVolume() - 10);
        if (event.key.code == sf::Keyboard::Key::Up)
          music.setVolume(music.getVolume() + 10);
        

        // Left and right to control tracking position
        if (event.key.code == sf::Keyboard::Key::Right){
          auto newPos = music.getPlayingOffset() + sf::seconds(5);
          music.setPlayingOffset(sf::Time(newPos));
        }
          
        if (event.key.code == sf::Keyboard::Key::Left){
          auto newPos = music.getPlayingOffset() - sf::seconds(5);
          if (newPos.asSeconds() <= 0.0f) newPos = sf::seconds(0);
          music.setPlayingOffset(sf::Time(newPos));
        }

        std::cout << "Current volume is :" << music.getVolume() << " position is: " 
          << music.getPlayingOffset().asSeconds() << std::endl;
      }
    }

    renderWindow.clear();
    renderWindow.display();
  }
}

 

You’ll notice that loading a music file is pretty much identical to loading any other asset in SFML.  Keep in mind the Music class actually owns the underlying data of the music that is played so it is not a light weight class so be careful when they are created.  However since the Music file is played from disk instead of from memory, it is safe to allocated multiple concurrent Music files, such as one per song played, without being hugely wasteful.

 

The code itself is fairly self explanitory.  You can set the volume directly on a music file that is being played, you can control music playback using vcr style play/pause/stop() controls.  You can also control the position of the sound using a combination of getPlayingOffset() and setPlayingOffset().  As you can see there are also time operators built into SFML such as sf::seconds() or sf::milliseconds() making time based math extremely simple.

 

There is a great deal more you can do with audio files, but we will cover that in the sound effects tutorial.

 

The Video

 

Programming , ,

26. October 2015

 

In the previous tutorial we look at the process of using sprites in SFML.  Today we are going to look instead at using a sprite sheet or texture atlas.  The process is very similar to working with a normal sprite, except that you have multiple sprites on a single texture.  Loading and swapping textures in memory is an expensive operation, so holding multiple sprites together can greatly improve the speed of your game.

 

As always there is an HD video version of this tutorial available here.

 

Many game engines have implicit support for spritesheets and sprite animation, however SFML does not.  There are however libraries built on top of SFML that provide this functionality or you can roll the required functionality yourself with relative ease.  Before we can continue we need a sprite sheet, which is simply one or more images with multiple frames of animation.  This is the one I am using:

dragonFrames

 

This isn’t the full sized image however.  The source file is actually 900x1200 pixels in size.  It should be noted that this size isn’t actually ideal.  Power of two texture dimensions should be preferred ( such as 512x256, 1024x1024, 2048x2048, etc. ).  In earlier version of OpenGL including OpenGL ES 1.x, a power of two texture was actually required.  These days, it is no longer a requirement, but a PoT texture generally will perform better.  As to file dimensions, you can fairly safely go up to 2048x2048 and support even rudimentary GPU’s like the Intel HD3000 series, but sizes of 4096x4096 are generally possible on most modern desktop and mobile GPUs.   You can notice from this image that it contains 12 textures, each 300x400 pixels in size.

 

Now we need code to extract a single frame from the texture and as you will see, it’s actually remarkably easy:

// Demonstrate creating a spritesheet
#include "SFML/Graphics.hpp"

int main(int argc, char ** argv){
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Demo Game");

  sf::Event event;
  sf::Texture texture;
  texture.loadFromFile("images/dragonFrames.png");

  sf::Sprite sprite(texture,sf::IntRect(0,0,300,400));


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

    renderWindow.clear();
    renderWindow.draw(sprite);
    renderWindow.display();
  }
}

 

This will draw just a small rectangular portion of our source texture, representing the first frame, like so:

image

 

Really that’s all that there is to it.  To add animation, we simply change the rectangular source after the fact, like so:

// Demonstrate creating a spritesheet
#include "SFML/Graphics.hpp"

int main(int argc, char ** argv){
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Demo Game");

  sf::Event event;
  sf::Texture texture;
  texture.loadFromFile("images/dragonFrames.png");

  sf::IntRect rectSourceSprite(300, 0, 300, 400);
  sf::Sprite sprite(texture,rectSourceSprite);
  sf::Clock clock;

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

    if (clock.getElapsedTime().asSeconds() > 1.0f){
      if (rectSourceSprite.left == 600)
        rectSourceSprite.left = 0;
      else
        rectSourceSprite.left += 300;

      sprite.setTextureRect(rectSourceSprite);
      clock.restart();
    }

    
    renderWindow.clear();
    renderWindow.draw(sprite);
    renderWindow.display();
  }
}

 

And when run:

GIF

 

You may notice right away that animation doesn’t look right and that’s a keen eye you’ve got there.  In this example we are simply going across the top three frames of animation from left to right.  The proper animation should actually be 0,1,2,1,0 not 0,1,2,0,1,2.  That said, in a proper game you would either roll your own animation class or use an existing one.  When we get to the process of creating a complete game, we will cover this process in detail.

 

In the above example we change frames of animation by changing the sprites source texture rect with a call to setTextureRect().  As I mentioned in the previous tutorial you could actually generate a new sprite per frame if preferred, as the sf::Sprite class is very light weight.

 

The Video

Programming , , ,

20. October 2015

 

In the previous tutorial we covered the basics of using graphics in SFML.  Chances are however your game isn’t going to be composed of simple shapes, but instead made up of many sprites.  That is exactly what we are going to cover today.

 

As always, there is an HD version of this tutorial available here

 

First off, we should start by defining what exactly a Sprite is.  In the early days of computers, sprite had special meaning as there was literally sprite hardware built into early 8bit computers.  A sprite is basically an image on screen that can move.  That’s it.   In SFML this relationship is easily demonstrated by it’s class hierarchy.

 

image

 

There is one very key concept to understand with sprites however.  A sprite in SFML represents and image or texture on screen that can be moved around.  However, it does not own the texture or image!  This makes the Sprite class fairly light weight, which certainly isn’t true about Texture or Image, the classes that actually contain all the data in the image.  Perhaps it’s easiest to start with a simple demonstration.

 

First we need an image to work with.  I am using a dragon sprite from the recent Humble Indie Gamedev Bundle.  The image looks like so:

dragonBig

 

Obviously you can use whatever image you want, just be sure to copy it into the working directory of your application.  In Visual Studio, the working directory can be located in the project’s properties panel under Debugging called Working Directory:

image

 

The image can be any of the following formats: bmp, hdr, gif, jpg, png, pic, psd, tga.  Keep in mind, not all formats are created equal.  Bitmap for example does not support transparency encoding and are generally quite large, but lose no image details and are simple to work with.  Gif has some patent issues and should generally be avoided.  Png seems like genuinely a good mix between features, size and quality and is well supported by content creation tools.

 

Ok, enough setup, let’s get to some code.

// Demonstrate sprite drawing in SFML
#include "SFML/Graphics.hpp"

int main(int argc, char ** argv){
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Demo Game");

  sf::Event event;

  sf::Texture texture;
  texture.loadFromFile("images/dragonBig.png");

  sf::Sprite sprite(texture);

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

    renderWindow.clear();
    renderWindow.draw(sprite);
    renderWindow.display();
  }
}

 

And when you run that:

image

 

As you can see, the experience is remarkably consistent to drawing using graphics primitives.  The big difference here is that we create our Sprite by providing a texture, which in turn we loaded from file with a call to Texture::loadFromFile().  There exist methods to load from stream or memory if preferred.  It is again important to remember that the Sprite does not own the Texture.  This means if the texture goes out of scope before the Sprite, the sprite will draw a blank rectangle.  This also means that several sprites can use the same texture.

 

Now you may have noticed that in addition to sf::Texture, there is a class called sf::Image and you may be wondering why.  There is one very simple difference at play here.  A Texture resides in the memory of your graphics card, while an image resides in system memory.  The act of copying an image from system memory to the GPU is quite expensive, so for performance reasons you almost certainly want to use Texture.  That said, Texture isn’t easily modified, so if you are working on a dynamic texture or say, creating a screen shot, Image is the better choice.  There exist methods to switch between the two types, but they are also fairly heavy in performance, so do not do them on a frame by frame basis.  At the end of the day

 

Let’s take a quick look at creating a dynamic image next.  Not something you are going to do often for most games granted, but it makes sense to mention it now.

// Demonstrate creating an Image
#include "SFML/Graphics.hpp"

int main(int argc, char ** argv){
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Demo Game");

  sf::Event event;

  sf::Image image;
  image.create(640, 480, sf::Color::Black);
  
  bool isBlackPixel = false;
  sf::Color blackPixel(0,0,0,255);
  sf::Color whitePixel(255, 255, 255, 255);

  //Loop through each vertical row of the image
  for (int y = 0; y < 480; y++){
    //then horizontal, setting pixels to black or white in blocks of 8
    for (int x = 0; x < 640; x++){


      if (isBlackPixel)
        image.setPixel(x, y, blackPixel);
      else
        image.setPixel(x, y, whitePixel);
      // Every 8th flip colour
      if (!(x % 8))
        isBlackPixel = !isBlackPixel;
    }
    // Offset again on vertical lines to create a checkerboard effect
    if(!(y%8))
      isBlackPixel = !isBlackPixel;
  }

  sf::Texture texture;
  texture.loadFromImage(image);
  sf::Sprite sprite(texture);

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

    renderWindow.clear();
    renderWindow.draw(sprite);
    renderWindow.display();
  }
}

 

When you run this example you should see:

image

 

Here you can see we can modify the pixels directly in our sf::Image.  However to display it on screen we still need to move it to texture and populate a sprite.  The difference is direct access to the pixel data.  Another important capability of sf::Image is the method saveToFile which enables you to well, save to file.  Obviously useful for creating screenshots and similar tasks.

 

You may notice depending on the resolution or composition of your source image that you texture may not look exactly like your source image.  This is because there is a smoothing or antialiasing filter built in to SFML to make images look smoother.  If you do not want this, perhaps going for that chunky 8bit look, you can turn it off with a call to setSmooth(false);

 

That is all we are going to cover today.  In the next tutorial part we will take a look at spritesheets, so we can have multiple different sprites in a single source image.

 

The Video

 

Programming , , ,

15. October 2015

 

In the previous tutorials we covered configuration, game loop and finally keyboard handling.  Today we are going to move on to the basics of graphics programming in SFML.  We are going to start with simple geographic primitives, then in the following tutorial we will move on to sprites.  You will notice right away that SFML is remarkably consistent in it’s approach to graphics, just like it is with Events.

 

As always, there is an HD video of this tutorial available here.

 

Let’s jump right in with a simple example that draws a blue circle on the screen.

// Demonstrate primitve drawing in SFML

#include "SFML/Graphics.hpp"

int main(int argc, char ** argv){
  sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Demo Game");

  sf::Event event;

  sf::CircleShape circleShape(200);
  circleShape.setFillColor(sf::Color::Blue);

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

    renderWindow.clear();
    renderWindow.draw(circleShape);
    renderWindow.display();
  }


}

Run this code and you will see:

image

This example creates a circle with a radius of 200 pixels that is filled with the colour blue.  Drawing is simply a matter of passing the shape into the draw() method of RenderWindow.  This is the way you draw pretty much everything in SFML.  If you take a look at the class reference for Drawable, the base class of any object passed into draw(), you can get a good idea of what classes are available.

image

 

As you can see, our CircleShape is part of that hierarchy.   Other than showing how to draw things to a window, this example shows us a few key concepts.  First, notice that we didn’t specify the location of our circle and by default it drew itself at the top left corner of the screen?  This shows us two critical things.  First, that the origin (0,0) of a window in SFML is the top left corner.  Second, that the origin/pivot ( the point within a shape a Drawable is drawn relative to ) is also it’s top left corner.  What if for example we wanted to position our circle relative to it’s midpoint instead?  Fortunately this is quite simple:

  sf::CircleShape circleShape(200);
  circleShape.setOrigin(circleShape.getRadius(), circleShape.getRadius());
  // or you could have calculated the mid point like so:
  // circleShape.setOrigin(circleShape.getLocalBounds().width / 2.0f, circleShape.getLocalBounds().height / 2.0f);

  circleShape.setFillColor(sf::Color::Blue);

Here we are setting the point draw calls are performed relative to by calling setOrigin().  This call sets that point in pixel coordinates relative to the top left corner of the Drawable.  Now this code will result in the following:

image

One other concept we didn’t cover is actually positioning our objects.  It is simply a matter of calling setPosition() like so:

circleShape.setPosition(100.0f, 100.0f);

This will result in the shape being drawn 100 pixels right and 100 pixels down from the top left corner of the window.  Of course the origin value is going to influence how that draw is performed.

 

Another important concept to cover is draw order.  Let’s throw in another circle, this time a red one, to illustrate what I mean:

    sf::CircleShape circleShape(200);
    circleShape.setFillColor(sf::Color::Blue);
    circleShape.setPosition(100.0f, 100.0f);

    sf::CircleShape circleShape2(200);
    circleShape2.setPosition(0.0f,0.0f);
    circleShape2.setFillColor(sf::Color::Red);
  
    //snip

    renderWindow.clear();
    renderWindow.draw(circleShape);
    renderWindow.draw(circleShape2);
    renderWindow.display();
  

 

Now run it and:

image

 

The order of draw calls is critically important.  Swap around the code, like so:

    renderWindow.clear();
    renderWindow.draw(circleShape2);
    renderWindow.draw(circleShape);
    renderWindow.display();

And you get:

image

 

As you can see, the later the draw call, the higher the z order.  Or put simply, things draw first are drawn first, then subsequent draw calls are drawn over top.  For future reference, this order is often referred to as the z-index.

 

Now that we have graphics to play with, there are a few things we can do with them…  such as move, rotate and scale.  Each of those functions transforms relative to the current position.  You can also directly set all three values using setPosition, setRotation and setScale.  With shapes, you also have control over the contour or line that composes the shape, like so:

  sf::CircleShape circleShape(200);
  circleShape.setFillColor(sf::Color::Blue);
  circleShape.setPosition(50.0f, 50.0f);
  circleShape.setOutlineThickness(10);
  circleShape.setOutlineColor(sf::Color::Green);

Here we set the line width to 10pixels and the color to green, resulting in:

image

 

As you may have noticed from the inheritance diagram earlier, there exist other shapes, ConvexShape and RectangleShape.  RectangleShape should be pretty self explanatory, bull ConvexShape requires a touch of explanation.  The Convex shape represents a convex hull, which is to say a closed shape of lines that never intersect or exceed 180 degrees.  You define a ConvexShape as a series of points, but it is important that you draw your shape in either a clockwise or counter-clockwise order so SFML knows how to draw it.  Here is an example creating a ConvexShape:

  sf::ConvexShape convexShape;
  convexShape.setPointCount(5);
  convexShape.setFillColor(sf::Color(147, 112, 227)); // PURPLE!
  convexShape.setOutlineThickness(3.0f);
  convexShape.setOutlineColor(sf::Color::White);
  convexShape.setPoint(0, sf::Vector2f(0.0f, 0.0f));
  convexShape.setPoint(1, sf::Vector2f(renderWindow.getSize().x, 0.0f));
  convexShape.setPoint(2, sf::Vector2f(renderWindow.getSize().x, renderWindow.getSize().y));
  convexShape.setPoint(3, sf::Vector2f(renderWindow.getSize().x / 2, renderWindow.getSize().y / 2));
  convexShape.setPoint(4, sf::Vector2f(0, renderWindow.getSize().y));


Resulting in

image

 

That’s it for basic graphics and shape rendering.  In the next tutorial we will expand upon this graphics knowledge and start looking at using sprites.

 

The Video

 

Programming , , ,

Month List

Popular Comments