CS 235 Unit 17 Exercise: Linking Third Party Libraries

Table of Contents


1. Introduction

About
In this exercise we are going to learn about linking third party libraries into our IDE to create more sophisticated C++ programs. In this case, we're going to use SFML, the Simple Fast Media Library, in order to make a really basic game.
Goals
  • See how to link a third party library.

2. Setting up the library

Windows users:

First, go to the SFML downloads page here: https://www.sfml-dev.org/download/sfml/2.5.1/. You will need to download a version based on whether you're using Visual Studio or Code::Blocks.

Visual Studio:

Download the latest version even if the year doesn't match. At time of writing, "Visual C++ 15 (2017) - xx-bit" is the version you should download. You can download the 32-bit or 64-bit version.

Code::Blocks:

  1. Navigate to where you have Codeblocks installed on your computer, such as "C:\Program Files\CodeBlocks\".
  2. Then, go to the "MinGW" folder, then the "bin" folder.
  3. Look for a "libgcc" dll file. We will know which SFML version to download based on this file.

c3_u17_ThirdPartyLibraries_libgcc.png

libgcc file Which SFML version to download
libgcc_s_seh-1.dll GCC 7.3.0 MinGW (SEH) - 64-bit
libgcc_s_sjlj-1.dll GCC 5.1.0 TDM (SJLJ) - Code::Blocks - 32-bit
libgcc_s_dw2-1.dll GCC 7.3.0 MinGW (DW2) - 32-bit

Once the library is downloaded, extract to an easy directory to find on your computer. For example, I usually have a "C:\Libraries\" folder on my computer, and so I'd extract SFML here - "C:\Libraries\SFML-2.5.1\".

Linux users:

Go to your package manager and search for "libsfml". Install the libsfml-dev package.

The files will be installed to "usr/include/SFML" and "usr/lib/x8664-linux-gnu" directories (at least that's where they're at on my computer.)

Mac users:

You will have to try to follow the Xcode guide on the SFML page (https://www.sfml-dev.org/tutorials/2.6/); I do not have a Mac to try to be able to setup SFML and write documentation with.

All users:

Within the SFML folder there are two important directories we care about: The lib folder and the include folder. You might keep these folders open or keep a notepad document open and paste your paths into that file for reference while we're setting up our project.


3. Part 1: Getting a test program running

Create a new project in Visual Studio or Code::Blocks. Right now we just need one file - main.cpp. The following code is the test program from the SFML setup documentation, you can copy-paste it into the main.cpp file:

#include <SFML/Graphics.hpp>

int main()
{
  sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
  sf::CircleShape shape(100.f);
  shape.setFillColor(sf::Color::Green);

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

      window.clear();
      window.draw(shape);
      window.display();
    }

  return 0;
}

It won't build at the moment, we still need to configure the project to use SFML.

For instructions on how to configure SFML with your IDE, look at the reference page:

../reference/third_party_libraries.html


4. Part 2: Implementing a basic game

Make sure to download the GameAssets folder: https://gitlab.com/moosadee/courses/-/tree/main/wip_exercises/starter_code/c3_u17_ThirdPartyLibraries/GameAssets?ref_type=heads Download the assets in that directory, bunny.png, diamond.png, grass.png, and PressStart2P.ttf. Copy these files into your SFML project's directory (where your .vcxproj is for Visual Studio, or your .cbp is for Code::Blocks).

We're going to keep everything in main.cpp for now so we can just focus on some basic SFML.

4.1. Additional #includes

At the top of the program, make sure you're including the following:

  • cmath
  • map
  • string

4.2. Handy functions

Add the following function to your program. You can copy/paste this above the int main() part in main.cpp. As long as they show up above main() you'll be able to use these functions within main().

sf::Vector2f GetRandomPosition( int screenWidth, int screenHeight )
{
  sf::Vector2f pos;
  pos.x = rand() % screenWidth - 64;
  pos.y = rand() % screenHeight - 64;
  return pos;
}
float GetDistance( sf::Vector2f obj1, sf::Vector2f obj2 )
{
  return sqrt( pow( obj1.x - obj2.x, 2 ) + pow( obj1.y - obj2.y, 2 ) );
}

4.3. Setting up the game

1. Create named constants for the window resolution: First, we’re going to define the screen width and height as named constants so we can refer to them in the program without having the numbers hard-coded all over the place (this is handy if you want to change the resolution later.)

const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;

2. Set up the game window: Then we need to create a RenderWindow and set it up. We will set the resolution via the VideoMode class and give the title bar the text “Example game”, as well as set our framerate.

sf::RenderWindow window( sf::VideoMode( SCREEN_WIDTH, SCREEN_HEIGHT ), "Example game" );
window.setFramerateLimit( 60 );

3. Load in images: We will create a map of textures so we can grab them by a string key, instead of having to deal with index numbers. We’re going to load each of the images.

map<string,sf::Texture> textures;
textures["bunny"].loadFromFile("bunny.png");
textures["diamond"].loadFromFile("diamond.png");
textures["grass"].loadFromFile("grass.png");

4. Load in a font: We’ll also create a Font variable and load in the font.

sf::Font font;
font.loadFromFile("PressStart2P.ttf");

5. Create a player sprite: Let’s create one Sprite for the player, set its texture and position, and create a couple other helper variables. (In a larger program, these should be in a class.)

sf::Sprite player;
player.setTexture( textures["bunny"] );
player.setPosition( SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 );
float playerSpeed = 5;
int playerScore = 0;

6. Create a diamond sprite: Let’s also create a Sprite for the diamond, the collectable item.

sf::Sprite item;
item.setTexture( textures["diamond"] );
item.setPosition( GetRandomPosition( SCREEN_WIDTH, SCREEN_HEIGHT ) );

7. Add score text: And a Text object to be able to render the player’s score to the screen.

sf::Text scoreText;
scoreText.setFont( font );
scoreText.setCharacterSize( 30 );
scoreText.setFillColor( sf::Color::White );
scoreText.setString( "Score: " + to_string( playerScore ) );

8. Add background tiles: Add a vector of sf::Sprites named groundTiles to make the background:

vector<sf::Sprite> groundTiles;
sf::Sprite ground;
ground.setTexture( textures["grass"] );
for ( int y = 0; y < SCREEN_HEIGHT; y += 32 )
  {
    for ( int x = 0; x < SCREEN_WIDTH; x += 32 )
      {
        ground.setPosition( x, y );
        groundTiles.push_back( ground );
      }
  }

These are all the setup parts, and we will add in the grass background later. Next, we need to create the game loop – the game will continue running until it gets a “close window” event.

4.4. Creating the game loop

Create the game loop. This will go after all the setup code.

while ( window.isOpen() )
  {
  }

And we'll add the following items within…

9. Listen for window close event: This code checks for any events happening, and if the event code is a “Closed” event, then close the window. This will cause the game to exit.

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

10. Listen for keyboard input: Next we’re going to listen for any keyboard presses. If an arrow key is pressed we are going to move the bunny by changing its x, y coordinates.

sf::Vector2f playerPos = player.getPosition();
if ( sf::Keyboard::isKeyPressed( sf::Keyboard::Left ) )
  {
    playerPos.x -= playerSpeed;
  }
 else if
   ( sf::Keyboard::isKeyPressed( sf::Keyboard::Right ) )
   {
     playerPos.x += playerSpeed;
   }
if ( sf::Keyboard::isKeyPressed( sf::Keyboard::Up ) )
  {
    playerPos.y -= playerSpeed;
  }
 else if
   ( sf::Keyboard::isKeyPressed( sf::Keyboard::Down ) )
   {
     playerPos.y += playerSpeed;
   }
player.setPosition( playerPos );

11. Check for collision between player and diamond: Now that we’ve handled events and inputs, the only game logic we need at the moment is to check if the Diamond and the Player are close to each other. We can use the GetDistance function here. You can adjust the value of 32, it is the amount of pixels of “distance”, and if the two objects are within the threshold, we will count it as a collision

if ( GetDistance( player.getPosition(), item.getPosition() ) < 32 )
  {
    // Count this as a collect
    item.setPosition( GetRandomPosition( SCREEN_WIDTH, SCREEN_HEIGHT ) );
    playerScore++;
    scoreText.setString( "Score: " + to_string( playerScore ) );
  }

c3_u17_ThirdPartyLibraries_collisionregion.png

12. Draw items to the screen: Finally within the game loop we are going to clear the screen and draw all our items.

window.clear();
// Draw all the backgrounds
for ( auto& tile : groundTiles )
  {
    window.draw( tile );
  }
// Draw item
window.draw( item );
// Draw player
window.draw( player );
// Draw text
window.draw( scoreText );
window.display();

13. Testing the program:

c3_u17_ThirdPartyLibraries_example1.png

When we run the program, the core bunny game should work. You can move the bunny around with the arrow keys and each time you collect a diamond the score should go up.

There are lots of ways you could customize or add onto this game, and feel free to experiment, but this is just an example of what you could do with additional libraries linked up in your IDE.


Author: Rachel Wil Sha Singh

Created: 2023-11-14 Tue 12:30

Validate