【问题标题】:sf::Music plays but not sf::Sound? Why?sf::Music 播放但 sf::Sound?为什么?
【发布时间】:2015-03-06 20:48:48
【问题描述】:

我正在学习 C++ 中的 SFML 库。我一直在尝试通过创建一个包含两个单独的 std::map 音乐 (sf::Music) 和声音 (sf::Sound) 的音频类来实现一种在游戏中组织音频的有效方法。但是,当我运行程序时,只能播放音乐而不能播放音效。我相信声音加载正常,因为它不会抛出错误消息。这是我的代码和信息。 (因为我是新人,所以可能也给我的代码提示:D) 提前致谢

VS2012,SFML 2.1

SFML_Snake.h(游戏头文件)

#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(游戏源文件)

/*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"));
}

【问题讨论】:

    标签: c++ audio sfml


    【解决方案1】:

    你基本上需要一个声音管理器,这是我用来管理声音的。

    头文件

    #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;
    };
    

    源文件

    #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();
            }
    
        }
    }
    

    现在你有了一个 SoundManager,你可以像这样加载声音并像这样播放声音。

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

    希望对您有所帮助,如果您需要更多帮助,请告诉我。

    【讨论】:

      【解决方案2】:

      sf::SoundBuffer 有效地保存了您要播放的音频数据。为此,只要您在播放数据,数据就必须存在。然而,在您的代码中,您将缓冲区加载到 Audio::loadAudio() 中,但是一旦您离开该函数,缓冲区就会被破坏,并且您的 sf::Sound 对象没有任何类型的数据可以播放。

      您宁愿存储sf::SoundBuffer 对象而不是sf::Sound 对象。

      【讨论】:

      • 那么我是否只需要在另一个函数(例如我的主函数)中将声音缓冲区设置为新声音才能播放?
      • 不,当您想要播放声音时,声音缓冲区必须存在。如果您只是加载它们然后让它们超出范围,就像您在Autio::loadAudio() 中所做的那样,音频数据不存在,并且由于不存在音频数据,因此无法播放声音。只需将声音缓冲区视为您硬盘上的 WAV 文件,如果它不再存在,您的音频播放器还能播放它吗?
      • 解决此问题的最佳方法是创建一个名为 SoundManager 的新类,该类存储 sf::SoundBuffer 的向量,然后创建一个 SoundManager,然后使用访问器访问您的向量并播放声音。
      • 我不一定推荐std::vector,因为它不是一个稳定的容器,所以如果容器扩展,它会重新分配自己并使所有引用失效,这意味着sf::Sound 对象会松开与缓冲区的“连接”(就像您在播放音频文件时移动它一样)。
      猜你喜欢
      • 1970-01-01
      • 2022-01-15
      • 1970-01-01
      • 1970-01-01
      • 2018-10-07
      • 2017-05-12
      • 2016-09-10
      • 2020-09-06
      • 2018-12-21
      相关资源
      最近更新 更多