codingbash
codingbash

Reputation: 1172

sf::Music plays but not sf::Sound? Why?

I am learning the SFML library in C++. I have been trying to implement an efficient method of organizing audio in my game by making an Audio class that contains two separate std::map for the music (sf::Music) and the sound (sf::Sound). However, when I run the program, only the music is able to play but not the sound effects. I believe the sound does load fine since it does not throw the error message. Here is my code and info. (Possibly give tips on my code as well since I am new :D ) Thanks in advance

VS2012, SFML 2.1

SFML_Snake.h (Game header file)

#pragma once
#ifndef GUARD_SFML_SNAKE
#define GUARD_SFML_SNAKE

#include "SFML/Audio.hpp"
#include "SFML/Graphics.hpp"
#include "Snake.h"
#include "Apple.h"
#include "Audio.h"
#include <iostream>

class SFML_Snake{
public:
    SFML_Snake();
    void run();
private:
    void checkBoundary(Snake);
    void checkApple(Snake&, Apple&, Audio& );
    std::vector<sf::RectangleShape> loadGrid();
private:
    bool processEvents();
    void update(Audio&);
    void render(std::vector<sf::RectangleShape>&);

public:
    sf::RenderWindow window;
    sf::Text textCount;
    Snake snake;
    Apple apple;
};

int main(){
    SFML_Snake start;
    start.run();
}
#endif

SFML_Snake.cpp (Game source file)

/*Import statements*/
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <SFML/Window.hpp>
#include <SFML/System.hpp>
#include "Snake.h"
#include "variables.h"
#include "Apple.h"
#include "Audio.h"
#include "SFML_Snake.h"
#include <iostream>
#include <vector>
#include <string>
#include <array>
#include <map>
#include <memory>


SFML_Snake::SFML_Snake():
window(sf::VideoMode(windowWidth, windowHeight), "SFML Application" ),
snake(Snake()), apple(Apple(0,0)), textCount(sf::Text())
{
    window.setFramerateLimit(FRAMERATE);
}



void SFML_Snake::checkBoundary(Snake s){
    for (int z = dots; z > 0; z--){
        if ((s.x[0] == s.x[z]) && (s.y[0] == s.y[z]))
            inGame = false;
    }
    if (s.y[0] >= windowHeight)
        inGame = false;
    if (s.y[0] < dotSize)
        inGame = false;
    if (s.x[0] >= windowWidth)
        inGame = false;
    if (s.x[0] < dotSize)
        inGame = false;
}

void SFML_Snake::checkApple(Snake& mA, Apple& mB, Audio& audios){
    if ((mA.x[0] == mB.x()) && (mA.y[0] == mB.y())){
        audios.getSound("eating").play();
        dots += dotInterval;
        points++;
        if(DEBUG)
        std::cout<< points << std::endl;
        textCount.setString(std::string("points: ") + std::to_string(points));
        mB.locateApple();
        for(int i = mA.draw().size() - 1; i >= 0; i--){
            while (((mA.x[0] == mB.x()) && (mA.y[0] == mB.y())) 
                || (0 == mB.x()) 
                || (0 == mB.y()) 
                || (windowWidth - dotSize/2 == mB.x()) 
                || (windowHeight - dotSize/2 == mB.y())) 
            {
                mB.locateApple();
            }
        }
    }
}

bool SFML_Snake::processEvents(){
    sf::Event event;
    while (window.pollEvent(event)){
            if (event.type == sf::Event::Closed)
                window.close();
        }
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Escape)) {
        return true;
    }
    snake.input();
    return false;
}
void SFML_Snake::update(Audio& audios){
        snake.checkReals();
        snake.moveUpdate();
        audios.getSound("moving").play();
        checkApple(snake, apple, audios);
        checkBoundary(snake);
}
void SFML_Snake::render(std::vector<sf::RectangleShape>& grid){

        std::vector<sf::RectangleShape> shapearray = snake.draw();
        for (int i = shapearray.size() - 1; i >= 0; i--){
            window.draw(shapearray[i]);
        }
        window.draw(apple.draw());
        for(int i = grid.size()-1; i>=0; i--){
            window.draw(grid[i]);
        }
        window.draw(textCount);
        window.display();
}
std::vector<sf::RectangleShape> SFML_Snake::loadGrid(){
    std::vector<sf::RectangleShape> grid;
    for(int k= dotSize/2; k<=windowHeight+dotSize/2; k+=dotSize){
            sf::RectangleShape line;
            line.setPosition(0, k-dotSize);
            line.setSize(sf::Vector2f(windowWidth, 1));
            line.setFillColor(sf::Color::Black);
            if(k==dotSize/2 || k == windowHeight + dotSize/2){
                line.setSize(sf::Vector2f(windowWidth, dotSize));
            }
            grid.push_back(line);
        }
    for(int i = dotSize/2; i<=windowWidth+dotSize/2; i+=dotSize){

        sf::RectangleShape line;
        line.setPosition(i-dotSize, 0);
        line.setSize(sf::Vector2f(1, windowHeight));
        line.setFillColor(sf::Color::Black);
        if(i==dotSize/2 || i == windowWidth+dotSize/2){
            line.setSize(sf::Vector2f(dotSize, windowHeight));
        }
        grid.push_back(line);

    }
    return grid;

}

void SFML_Snake::run(){
    /*Initialize the objects*/

    std::vector<sf::RectangleShape> grid = loadGrid();
    if(!DEBUG)
        std::cout<<"DEBUG MODE: OFF" <<std::endl;
    Audio& audios = Audio();
    apple.locateApple();

    /*Load the audio*/

    audios.getMusic("backgroundMusic").setVolume(10);
    audios.getMusic("backgroundMusic").setLoop(true);
    audios.getMusic("backgroundMusic").setVolume(25);

    /*Load the font*/
    sf::Font font;
    if (!(font.loadFromFile("arial.ttf")))
        if(DEBUG)
            std::cout << "Error loading fonts" << std::endl;
    /*Create the text*/
    textCount.setFont(font);
    textCount.setString(std::string("points: ") + std::to_string(points));
    textCount.setColor(sf::Color::Red);
    textCount.setCharacterSize(20);
    textCount.setPosition(windowWidth / 2 - (textCount.getString().getSize()*(textCount.getCharacterSize() / 5)), textCount.getCharacterSize() - 10);
    textCount.setStyle(sf::Text::Bold);
    window.draw(textCount);

    /*MAIN GAME LOOP*/
    counterTick = 1;

    audios.getSound("begin").play();
    audios.getMusic("backgroundMusic").play();
    while (inGame && !pause)
    {
        std::string counter = std::to_string(counterTick);
        if(DEBUG)
            std::cout << "Tick: " + counter << std::endl;

        window.clear(sf::Color::White);
        if(processEvents()){
            break;
        }
        update(audios);
        render(grid);
        snake.secInput = false;
        counterTick++;
    }
    audios.getSound("losing").play();
    audios.getMusic("backgroundMusic").stop();
    std::system("PAUSE");//bad practice, debuggin purposes
}

Audio.h

#pragma once
#ifndef GUARD_AUDIO_H
#define GUARD_AUDIO_H
#include "variables.h"
#include "SFML\Graphics.hpp"
#include "SFML\Audio.hpp"
#include <memory>

struct Audio{
    std::map<std::string, sf::Sound> sounds;
    std::map<std::string, std::unique_ptr<sf::Music>> musics;
    //std::map<std::string, sf::Sound> sounds;
    //std::map<std::string, sf::Music> musics;

    Audio();

    void Audio::addSound(sf::Sound&, sf::SoundBuffer& , const std::string&);

    void Audio::addSound(sf::Sound&, const std::string&);

    void Audio::addMusic(const std::string&, std::unique_ptr<sf::Music> );

    sf::Sound &Audio::getSound(std::string);

    sf::Music &Audio::getMusic(std::string);

    void Audio::loadAudio();
};

#endif//GUARD_AUDIO_H

Audio.cpp

#include "Audio.h"
#include <iostream>
    Audio::Audio(){
        loadAudio();
    }
    void Audio::addSound(sf::Sound& s, sf::SoundBuffer& sb, const std::string &key){
        s.setBuffer(sb);
        sounds.insert(std::pair<std::string, sf::Sound>(key, std::move(s)));
    }
    void Audio::addSound(sf::Sound& s, const std::string &key){
        sounds.insert(std::pair<std::string, sf::Sound>(key, s));
    }
    void Audio::addMusic(const std::string &key, std::unique_ptr<sf::Music> value){
        musics.insert(std::pair<std::string, std::unique_ptr<sf::Music> >(key, std::move(value)));
    }
    sf::Sound &Audio::getSound(std::string key){
        return sounds.at(key);
    }
    sf::Music &Audio::getMusic(std::string key){
        return *musics.at(key);
    }
    void Audio::loadAudio(){

    //sf::Music backgroundMusic;
    sf::Sound s_eating;
    sf::SoundBuffer sb_eating;
    sf::Sound s_moving;
    sf::SoundBuffer sb_moving;
    sf::Sound s_losing;
    sf::SoundBuffer sb_losing;
    sf::Sound s_begin;
    sf::SoundBuffer sb_begin;

    auto backgroundMusic = std::unique_ptr<sf::Music>(new sf::Music());

    if (!backgroundMusic->openFromFile("backgroundmusic.wav"))
        if(DEBUG)
            std::cerr << "Error opening \"backgroundmusic.wav\"" << std::endl;
    if (!sb_eating.loadFromFile("eatingsfx.wav"))
        if(DEBUG)
            std::cerr << "Error opening \"eatingsfx.wav\"" << std::endl;
    if (!sb_moving.loadFromFile("movingsfx.wav"))
        if(DEBUG)
            std::cerr << "Error opening \"movingsfx.wav\"" << std::endl;
    if (!sb_losing.loadFromFile("losingsfx.wav"))
        if(DEBUG)
            std::cerr << "Error opening \"losingsfx.wav\"" << std::endl;
    if (!sb_begin.loadFromFile("beginsfx.wav"))
        if(DEBUG)
            std::cerr << "Error opening \"beginsfx.wav\"" << std::endl;

    //s_eating.setBuffer(sb_eating);
    //s_moving.setBuffer(sb_moving);
    //s_losing.setBuffer(sb_losing);
    //s_begin.setBuffer(sb_begin);
    addMusic(std::string("backgroundMusic"), std::move(backgroundMusic));
    addSound(s_eating, sb_eating, std::string("eating"));
    addSound(s_moving, sb_moving, std::string("moving"));
    addSound(s_losing, sb_losing, std::string("losing"));
    addSound(s_begin, sb_begin, std::string("begin"));
}

enter image description here

Upvotes: 1

Views: 2327

Answers (2)

Canvas
Canvas

Reputation: 5897

You basically need a sound manager, this is what I use to manager my sounds.

Header file

#pragma once

#include "SFML/Audio.hpp"
#include "Enums.h"
#include <map>
#include <vector>
#include <iostream>

class SoundLoader
{
public:
    //SoundNames is an enum
    SoundLoader();
    ~SoundLoader();

    void LoadSounds();
    void PlaySound(SoundNames soundName);

    std::map<SoundNames, sf::SoundBuffer> Sounds;
    std::vector<sf::Sound> playingSounds;
};

Source file

#include "SoundLoader.h"

SoundLoader::SoundLoader()
{

}

SoundLoader::~SoundLoader()
{

}

void SoundLoader::LoadSounds()
{
    Sounds[SoundNames::sound1].loadFromFile("Assets/Sounds/sound1.wav");
}

void SoundLoader::PlaySound(SoundNames soundName)
{
    if (playingSounds.size() == 0)
    {
        playingSounds.push_back(sf::Sound());
        playingSounds.at(0).setBuffer(Sounds[soundName]);
        playingSounds.at(0).play();
    }
    else
    {
        int location = -1;
        for (int i = 0; i < playingSounds.size(); i++)
        {
            if (playingSounds.at(i).getStatus() != sf::Sound::Playing && location == -1)
            {
                location = i;
            }
        }

        if (location != -1)
        {
            playingSounds.at(location).setBuffer(Sounds[soundName]);
            playingSounds.at(location).play();
        }
        else
        {
            playingSounds.push_back(sf::Sound());
            playingSounds.at(playingSounds.size()-1).setBuffer(Sounds[soundName]);
            playingSounds.at(playingSounds.size() - 1).play();
        }

    }
}

Now you have yourself a SoundManager, you can load sounds like so and play sounds like so.

SoundLoader sl;
sl.LoadSounds();
sl.Play(SoundNames::sound1);

Hope this helps you out, if you need any more help just let me know.

Upvotes: 2

Lukas
Lukas

Reputation: 2613

The sf::SoundBuffer effectively holds the audio data you want to playback. To do so the data needs to exist as long as you're playing it. In your code however, you load the buffers in Audio::loadAudio() but as soon as you leave that function, the buffer will get destroyed and your sf::Sound object don't have any kind of data to playback.

You rather want to store the sf::SoundBuffer objects instead of the sf::Sound objects.

Upvotes: 0

Related Questions