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

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - Discover-

Pages: [1]
1
Hello everybody,

Today I decided to re-write the design/logic in my Sound class (renamed to Audio) (it used to work before the re-write but the design was bad) by storing a std::string and a sf::SoundBuffer in a std::map in the class and then loading all .wav files into this map on start-up of the application (later on moving this to a separate thread, of course). A  new issue had arisen so I started throwing around breakpoints and came to the conclusion that it for whatever reason seems to not ever load the sfml-audio-d-2.dll, even though it is in place with all other .dll's. Here a screenshot of the error:


(take a look at the Watch window)

Showing that it did in fact find the song we are trying to play (different sound being played):


As for the .dll's:


Now as for the code, it can all be found on this GitHub repository, but I'll paste some code regarding the issue here anyhow.

audio.h
#pragma once

#include <vector>
#include <array>
#include <map>
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <iostream>

class Game;

class Audio
{
    public:
        Audio(Game* _game);
        ~Audio();

        bool Load(std::string filename);
        void Play(std::string filename, bool loop = false);
        void Stop(std::string filename);
        void SetVolume(std::string filename, float volume);
        float GetVolume(std::string filename);
        void SetLoop(std::string filename, bool val);
        bool IsLooping(std::string filename);
        sf::SoundSource::Status GetStatus(std::string filename);
        sf::Sound* GetPlayingSound(std::string filename);

    private:
        Game* game;
        std::map<std::string, sf::SoundBuffer> soundBuffers;
};
 

audio.cpp
#include "audio.h"
#include "game.h"
#include <SFML/Audio.hpp>

Audio::Audio(Game* _game)
{
    game = _game;
}

Audio::~Audio()
{

}

bool Audio::Load(std::string filename)
{
    sf::SoundBuffer buffer;

    if (buffer.loadFromFile(filename))
    {
        soundBuffers[filename] = buffer;
        return true;
    }
    else
        std::cout << "Audio::Load: Could not find audio file '" << filename << "'" << std::endl;

    return false;
}

void Audio::Play(std::string filename, bool loop /* = false */)
{
    std::map<std::string, sf::SoundBuffer>::iterator itr = soundBuffers.find(filename);

    if (itr != soundBuffers.end())
    {
        sf::Sound playingSound = sf::Sound((*itr).second);

        playingSound.play();

        if (loop)
            playingSound.setLoop(true);

        if (game->IsMusicMuted())
            playingSound.setVolume(0.0f);
    }
    else
        std::cout << "Audio::Play: Could not find audio file '" << filename << "'" << std::endl;
}

void Audio::Stop(std::string filename)
{
    if (filename == "all")
    {
        for (std::map<std::string, sf::SoundBuffer>::iterator itr = soundBuffers.begin(); itr != soundBuffers.end(); ++itr)
            sf::Sound((*itr).second).stop();
    }
    else
    {
        if (sf::Sound* playingSnd = GetPlayingSound(filename))
            playingSnd->stop();
        else
            std::cout << "Audio::Stop: Could not find audio file '" << filename << "'" << std::endl;
    }
}

void Audio::SetVolume(std::string filename, float volume)
{
    if (filename == "all")
    {
        for (std::map<std::string, sf::SoundBuffer>::iterator itr = soundBuffers.begin(); itr != soundBuffers.end(); ++itr)
            sf::Sound((*itr).second).setVolume(volume);
    }
    else
    {
        if (sf::Sound* playingSnd = GetPlayingSound(filename))
            playingSnd->setVolume(volume);
        else
            std::cout << "Audio::SetVolume: Could not find audio file '" << filename << "'" << std::endl;
    }
}

float Audio::GetVolume(std::string filename)
{
    if (sf::Sound* playingSnd = GetPlayingSound(filename))
        return playingSnd->getVolume();
    else
        std::cout << "Audio::GetVolume: Could not find audio file '" << filename << "'" << std::endl;

    return 0.0f;
}

void Audio::SetLoop(std::string filename, bool val)
{
    if (filename == "all")
    {
        for (std::map<std::string, sf::SoundBuffer>::iterator itr = soundBuffers.begin(); itr != soundBuffers.end(); ++itr)
            sf::Sound((*itr).second).setLoop(val);
    }
    else
    {
        if (sf::Sound* playingSnd = GetPlayingSound(filename))
            playingSnd->setLoop(val);
        else
            std::cout << "Audio::SetLoop: Could not find audio file '" << filename << "'" << std::endl;
    }
}

bool Audio::IsLooping(std::string filename)
{
    if (sf::Sound* playingSnd = GetPlayingSound(filename))
        return playingSnd->getLoop();
    else
        std::cout << "Audio::IsLooping: Could not find audio file '" << filename << "'" << std::endl;

    return false;
}

sf::SoundSource::Status Audio::GetStatus(std::string filename)
{
    if (sf::Sound* playingSnd = GetPlayingSound(filename))
        return playingSnd->getStatus();
    else
        std::cout << "Audio::GetStatus: Could not find audio file '" << filename << "'" << std::endl;

    return sf::SoundSource::Stopped;
}

sf::Sound* Audio::GetPlayingSound(std::string filename)
{
    std::map<std::string, sf::SoundBuffer>::iterator itr = soundBuffers.find(filename);

    if (itr != soundBuffers.end())
        return &sf::Sound((*itr).second);

    return NULL;
}

Loading the audio (done using the Dirent library to load all files from a given directory)
void Game::LoadAllAudio()
{
    DIR* dir;
    struct dirent* ent;
    std::stringstream ss;
    audio = new Audio(this);

    if ((dir = opendir("Audio")) != NULL)
    {
        while ((ent = readdir(dir)) != NULL)
        {
            if (ent->d_name[0] != '.') //! These seem to be the only hidden invisible files in there and the dirent library doesn't offer detection for it, so this will work. :)
            {
                ss << "Audio/" << ent->d_name;
                audio->Load(ss.str().c_str());
                ss.str(std::string());
            }
        }

        closedir(dir);
    }
}

Playing the audio (example)
Menu::Menu(Game* _game)
{
    game = _game;
    selectedOption = 1;
    currentMenu = MENU_MAIN;
    newMenu = MENU_NONE;
    movingCurrMenuOut = false;
    movingNewMenuIn = false;
    game->GetAudio()->Play("Audio/menu_music.wav", true);
}

Hope that is enough!

Thanks for reading,

Jasper

2
Graphics / 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! :)

Pages: [1]
anything