Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Tilemap using sprites  (Read 3143 times)

0 Members and 1 Guest are viewing this topic.

Taharrie

  • Newbie
  • *
  • Posts: 2
    • View Profile
Tilemap using sprites
« on: December 25, 2015, 08:39:30 pm »
Hello everybody!

My (nick)name is Taharrie and I am learning SFML. So far, I really enjoy learning it. Recently, I started to create some sort of tile-map system for a game, so I could design maps / levels fairly easy.

However, it seems that I have messed up somewhere. When I run my code, the correct map shows up, but the frames per second are insanely low! I know my laptop is not a fast one, but 60 frames per second should be achievable. I hope somebody notices my error and give me some hints to get me back on track.

Note: I understand that vertex arrays are much faster, but I do not feel very comfortable with them. I will learn them later on.

My code is separated into classes and whenever I leave out the tile-map part, I get my 60 frames per second...

My code currently looks like this (C++ & SFML 2:

Map.h:

#pragma once
#include "SFML/Graphics.hpp"
#include <iostream>

class Map
{
public:
        Map();
        void update(sf::RenderWindow &window);

private:
        // The width and height of a tile in pixels
        const int tileWidth = 30;
        const int tileHeight = 30;

        // Add a new texture when a new tile is added
        sf::Texture tFloor;
        sf::Texture tWoodenBox;
        sf::Texture tStoneWall;
        sf::Texture tPinkPath;
};
 


Map.cpp:

#include "Map.h"

Map::Map()
{
        // Initialize the textures that are going to be used
        // UPDATE THIS IF-STATEMENT WHEN A NEW TEXTURE IS ADDED
        if (
                !tFloor.loadFromFile("Assets/Map/floor.png") ||
                !tWoodenBox.loadFromFile("Assets/Map/wood.png") ||
                !tStoneWall.loadFromFile("Assets/Map/stone.png") ||
                !tPinkPath.loadFromFile("Assets/Map/pink_path.png")
                )
        {
                std::cout << "ERROR => could not load the tile textures!" << std::endl;
        }
}

void Map::update(sf::RenderWindow &window)
{
        /*
        The codes with their corresponding texture names
        - 0     =>      floor
        - 1     =>      stone wall
        - 2     =>      wooden box
        - 3     =>      pink path
        */


        const int rowAmount = 20;
        const int columnAmount = 20;

        const int map[rowAmount][columnAmount] =
        {
                { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // row 1
                { 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1 }, // row 2
                { 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1 }, // row 3
                { 1, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 1 }, // row 4
                { 1, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 1 }, // row 5
                { 1, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 1 }, // row 6
                { 1, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 1 }, // row 7
                { 1, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 1 }, // row 8
                { 1, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 1 }, // row 9
                { 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1 }, // row 10
                { 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1 }, // row 11
                { 1, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 1 }, // row 12
                { 1, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 1 }, // row 13
                { 1, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 1 }, // row 14
                { 1, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 1 }, // row 15
                { 1, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 2, 0, 0, 0, 0, 2, 3, 3, 1 }, // row 16
                { 1, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 1 }, // row 17
                { 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1 }, // row 18
                { 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1 }, // row 19
                { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // row 20
        };

        // Loop through the rows
        for (int row = 0; row < rowAmount; row++)
        {
                // Loop through the columns
                for (int column = 0; column < columnAmount; column++)
                {
                        // Temporary place to store the current texture and sprite
                        sf::Texture textureToApply;
                        sf::Sprite spriteHolder;

                        // Apply the corresponding texture
                        // To add a new tile, add a new "else if()"-statement
                        if (map[row][column] == 0)
                        {
                                textureToApply = tFloor;
                        }
                        else if (map[row][column] == 1)
                        {
                                textureToApply = tStoneWall;
                        }
                        else if (map[row][column] == 2)
                        {
                                textureToApply = tWoodenBox;
                        }
                        else if (map[row][column] == 3)
                        {
                                textureToApply = tPinkPath;
                        }

                        // Appy the texture to the sprite placeholder
                        spriteHolder.setTexture(textureToApply);

                        // Set the correct position
                        // The columns represent the X, the rows the Y
                        spriteHolder.setPosition(column * tileWidth, row * tileHeight);

                        // Draw the sprite to the screen before looping again
                        window.draw(spriteHolder);
                }
        }
}
 

Part of main.cpp:

[...]
window.clear();
map.update(window);
window.display();
[...]
 

I try to make use of good commenting habits as I code, but if any explanations on certain bits are needed, I would be happy to provide them.

Merry Christmas!

Thanks in advance,

Taharrie

G.

  • Hero Member
  • *****
  • Posts: 1593
    • View Profile
Re: Tilemap using sprites
« Reply #1 on: December 25, 2015, 10:08:17 pm »
In Map::update you copy textures to textureToApply a LOT. Avoid copying textures, it's slow.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Tilemap using sprites
« Reply #2 on: December 26, 2015, 01:33:09 am »
On top of what G said about copying textures around, you're actually creating and destroying a new texture and sprite for each tile. Minor improvement would be to create them before the loops and just modify them inside.

Major improvement would be to consider using a vertex array. There is a tile map example in the tutorials on vertex arrays.

Consider putting all of your textures into a single image file and using a single texture (this would be required for that vertex array example).

If, for now, you need the four textures and you still want to create the sprite for every tile, consider using a pointer/reference to the texture instead of a new texture. This would solve the texture copying issue.
e.g. create the pointer to the texture, set it to point to which texture you wish to use from the ifs, then set the sprite's texture as the texture at the pointer.
(or you could just set the sprite's texture directly in the ifs so that the internal texture/texture-pointer is not required)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Taharrie

  • Newbie
  • *
  • Posts: 2
    • View Profile
Re: Tilemap using sprites
« Reply #3 on: December 26, 2015, 11:58:29 am »
Hello!

Thank you all for the fast replies. I think I am going to use vertex arrays. I already planned on doing so, but it seemed rather difficult to learn at first.

Just for learning purposes, I will use some pointers to speed it up.

This piece of code taught me a lot and I think I can "convert" it to vertex arrays, or at least use the concepts.

Hapax and G, you guys are great. Quick reply and helpful.

Have a nice day and thanks again!

Merry Christmas.

Taharrie