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

Author Topic: Performance drop when loading map from .txt  (Read 1869 times)

0 Members and 1 Guest are viewing this topic.

Discover-

  • Newbie
  • *
  • Posts: 8
    • View Profile
Performance drop when loading map from .txt
« on: June 05, 2013, 04:51:49 pm »
Hello everybody,

I've started working on my own platformer game with the help of SFML after getting slightly tired of SDL and I've ran into my first 'big' problem that I have had no success solving on my own so far. When I woke up this morning I decided I wanted to implement at least a proper Level class which loads and draws the map based on the level it's loaded from (which is a .txt file). The problem is that the FPS is now at max 8 FPS because I load all images, set the texture of the sprite to this image, set their position AND draw it every update call unlike I did previously (only drawing in the game loop). The issue, however, is that I want to not hardcode the amount in an array like I did in the Game class but store it in a vector properly but I have no idea how to properly do this.

The level (.txt) I am testing:
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
9 1 1 1 9 9 9 9 9 9 2 2 2 2 2 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 2 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 2 1 2 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
2 2 2 2 2 2 2 2 2 2 9 9 9 9 9 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 9 9 9 9 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 9 9 9 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 9 9 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

How the level looks:


The current code using to load the levels:
void Level::LoadMap(const char* filename)
{
    std::ifstream openfile(filename);
    std::string line;
    std::vector<int> tempVector;

    while (std::getline(openfile, line))
    {
        for (int i = 0; i < line.length(); i++)
        {
            if (line[i] != ' ')
            {
                char value[1] = { line[i] };
                tempVector.push_back(atoi(value));
            }
        }

        mapVector.push_back(tempVector);
        tempVector.clear();
    }

    for (int i = 0; i < mapVector.size(); i++)
    {
        for (int j = 0; j < mapVector[i].size(); j++)
        {
            std::string randNumb = std::to_string(long double(urand(0, 1)));

            switch (mapVector[i][j])
            {
                case 9:
                    fileArray[i][j] = "Graphics/Tiles/sky_3.png"; //! Empty sky block
                    break;
                case 0:
                    fileArray[i][j] = "Graphics/Tiles/sky_" + std::to_string(long double(urand(0, 20) < 16 ? 3 : urand(0, 2))) + ".png";
                    break;
                case 1:
                    fileArray[i][j] = "Graphics/Tiles/dirt_" + randNumb + ".png";
                    break;
                case 2:
                    fileArray[i][j] = "Graphics/Tiles/dirt_rock_" + randNumb + ".png";
                    break;
                case 3:
                    fileArray[i][j] = "Graphics/Tiles/grass_" + randNumb + ".png";
                    break;
                case 4:
                    fileArray[i][j] = "Graphics/Tiles/grass_ontop_" + randNumb + ".png";
                    break;
                case 5:
                    fileArray[i][j] = "Graphics/Tiles/ground_" + randNumb + ".png";
                    break;
                case 6:
                    fileArray[i][j] = "Graphics/Tiles/sand_" + randNumb + ".png";
                    break;
                default:
                    return;
            }
        }
    }
}

Code to draw the map (called right after window.clear() in Game class' loop:
void Level::DrawMap(sf::RenderWindow &window)
{
    sf::Sprite sprite;
    sf::Texture image;
    Player* player = game->GetPlayer();

    for (int i = 0; i < mapVector.size(); i++)
    {
        for (int j = 0; j < mapVector[i].size(); j++)
        {
            //! ONLY draw the images if the player is within visibility distance, else there's no point in wasting performance.
            if (IsInRange(player->GetPositionX(), j * 50.0f, player->GetPositionY(), i * 50.0f, 600.0f))
            {
                // Here is the problem
                image.loadFromFile(fileArray[i][j]);
                sprite.setTexture(image);
                sprite.setPosition(j * 50.0f, i * 50.0f);
                window.draw(sprite);
            }
        }
    }
}



So that's it for the current way of initializing and drawing the tiles. The previous way - which was NOT having ANY performance issues at ALL - is as following:

int Game::Update()
{
    ...
    sf::Texture imageDirt[2];
    sf::Texture imageGrass[2];
    sf::Texture imageGround[2];
    sf::Texture imageSky[4];
    sf::Sprite spriteDirt[15][60];
    sf::Sprite spriteGrass[12][60];
    sf::Sprite spriteGround[12][60];
    sf::Sprite spriteSky[12][60];

    for (int i = 0; i < 4; ++i)
    {
        std::string numberInStr = std::to_string(long double(i));

        if (i < 2)
        {
            imageDirt[i].loadFromFile("Graphics/Tiles/dirt_" + numberInStr + ".png");
            imageGrass[i].loadFromFile("Graphics/Tiles/grass_" + numberInStr + ".png");
            imageGround[i].loadFromFile("Graphics/Tiles/ground_" + numberInStr + ".png");
        }

        imageSky[i].loadFromFile("Graphics/Tiles/sky_" + numberInStr + ".png");
    }

    for (int i = 7; i < 9; ++i)
        for (int j = 0; j < 60; ++j)
            spriteGrass[i][j].setTexture(imageGrass[urand(0, 1)]);

    for (int i = 9; i < 12; ++i)
        for (int j = 0; j < 60; ++j)
            spriteGround[i][j].setTexture(imageGround[urand(0, 1)]);

    for (int i = 12; i < 15; ++i)
        for (int j = 0; j < 60; ++j)
            spriteDirt[i][j].setTexture(imageDirt[urand(0, 1)]);

    for (int i = 0; i < 12; ++i)
        for (int j = 0; j < 60; ++j)
            spriteSky[i][j].setTexture(imageSky[(i > 7 || urand(0, 20) < 16) ? 3 : urand(0, 2)]);

    float boxX = 0.0f, boxY = 0.0f;

    //! Filling up skybox
    for (int i = 0; i < 12; ++i)
    {
        for (int j = 0; j < 60; ++j)
        {
            spriteSky[i][j].setPosition(boxX, boxY);
            boxX += 50.0f;
        }

        boxX = 0.0f;
        boxY += 50.0f;
    }

    //! Filling up grass
    boxX = 0.0f;
    boxY = 250.0f;

    for (int i = 7; i < 9; ++i)
    {
        for (int j = 0; j < 60; ++j)
        {
            spriteGrass[i][j].setPosition(boxX, boxY);
            boxX += 50.0f;
        }

        boxX = 0.0f;
        boxY += 50.0f;
    }

    ... etc.

    //! Sky blocks are not collidable.
    for (int i = 0; i < 12; ++i)
        for (int j = 0; j < 60; ++j)
            gameObjects.push_back(spriteSky[i][j]);

    for (int i = 9; i < 12; ++i)
    {
        for (int j = 0; j < 60; ++j)
        {
            gameObjects.push_back(spriteGround[i][j]);
            gameObjectsCollidable.push_back(spriteGround[i][j]);
        }
    }

    ...etc
    ...

    while (window.isOpen())
    {
        ...
        window.clear();

        for (int i = 0; i < 12; ++i)
            for (int j = 0; j < 60; ++j)
                window.draw(spriteSky[i][j]);

        for (int i = 9; i < 12; ++i)
            for (int j = 0; j < 60; ++j)
                window.draw(spriteGround[i][j]);

        for (int i = 7; i < 9; ++i)
            for (int j = 0; j < 60; ++j)
                window.draw(spriteGrass[i][j]);

        for (int i = 12; i < 15; ++i)
            for (int j = 0; j < 60; ++j)
                window.draw(spriteDirt[i][j]);

        ...

        window.setView(view);

        float fps = 1 / fpsClock.getElapsedTime().asSeconds();

        sf::Text text("FPS: " + std::to_string(long double(int(fps))), font, 15);
        text.setColor(sf::Color::Black);
        text.setPosition(436 + player->GetPositionX(), 15.0f);
        window.draw(text);

        window.display();
    }

    return 0;
}





I hope you guys are able to help me out here. If you wish to see the entire code, it's all on GitHub here: https://github.com/Discover-/Platformer-SFML/commits/.

Thanks in advance!

Greetings,

Discover- / Jasper

P.S. It's a shame there's no spoiler tags, they'd be really useful in cases like this post! :)
« Last Edit: June 05, 2013, 05:49:08 pm by Discover- »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Performance drop when loading map from .txt
« Reply #1 on: June 05, 2013, 05:59:21 pm »
You reload the images constantly. Load them once at startup and just use them in the draw function.
Laurent Gomila - SFML developer

Discover-

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Performance drop when loading map from .txt
« Reply #2 on: June 06, 2013, 02:11:32 am »
I figured out the problem and rewrote the 'system' and not it works again. Thanks :)