【问题标题】:How to play a sf::Sound in a loop?如何循环播放 sf::Sound?
【发布时间】:2021-12-02 11:44:06
【问题描述】:

我们(学校)正在使用 SFML 用 C++ 开发游戏。该游戏是一款格斗游戏,例如玩家被击中时我们需要播放一些声音。

我正在尝试循环播放 sf::Sound。我知道我们不应该在循环中调用 sf::Sound 的 play() 方法,但是由于 SFML 应用程序都在 while 循环中运行,我别无选择。或者至少,我不知道有其他方法可以做到这一点。

我尝试使用sound manager,我阅读了多篇关于它的帖子,但我发现没有任何效果。

这是一个示例代码:

#include <SFML/Audio.hpp>

#include <vector>
#include <iostream>

int main() {
    int FPS = 60;

    //    sf::Music music;
    //    if(!music.openFromFile("resources/audio/fight_theme.ogg")) {
    //        std::cout << "Music was not found" << std::endl;
    //    }
    //    music.setVolume(10.f);
    //    music.play();

    // Create the main window
    sf::VideoMode desktopMode = sf::VideoMode::getDesktopMode();
    sf::RenderWindow app(
        sf::VideoMode(
            desktopMode.width,
            desktopMode.height,
            desktopMode.bitsPerPixel),
        "SkyddaForStackOverflow",
        sf::Style::Fullscreen
    );
    app.setFramerateLimit(FPS);

    //Main loop
    while (app.isOpen()) {
        /*In the actual code, we have two player instances.
        When the user press S or keyDown button, we call the attack function.
        In the function, we deal the damages to the ennemy, then we call playSound
        to play the hitting sound

        Please note this is a sample code to help understanding the case.
        In the actual code, everything is delegated to the Player class, to a SoundLoader (which is basically playSound() here)
        The problem is, even with delegation, even if the playSound method is not situated in the main loop,
        it is called in the main loop so the location of the code does not make any difference : it won't play since it won't
        be called outside of a loop as we do for the background music (see commented code after main() {..., the background music
        works fine.*/
        if(player.attack(ennemy)) {
            playSound();
        }
    }

    return EXIT_SUCCESS;
}

void playSound() {
    sf::SoundBuffer buffer;
    if(!buffer.loadFromFile(path)) {
        std::cout << "Sound was not found at " << path << std::endl;
    }
    sf::Sound sound(buffer);
    sound.play();
}

如果您还有其他问题,请不要犹豫。 谢谢!

【问题讨论】:

    标签: c++ sfml


    【解决方案1】:

    问题不在于“在循环外被调用”;问题是您的 sf::Sound 对象在 playSound 函数结束时被销毁!

    首先,定义两个全局(或类)变量:

    std::map<std::string, sf::SoundBuffer> buffers;
    std::map<std::string, sf::Sound> sounds;
    

    您现在可以如下定义playSound

    void playSound(std::string path) {
      if (auto it = sounds.find(path); it == sounds.end()) {
        bool ok = buffers[path].loadFromFile(path);
        // do something if ok is false
        sounds[path] = sf::Sound{buffers[path]};
      }
      sounds[path].play();
    }
    

    这将使您的sf::Sound 对象(和关联的sf::SoundBuffers)保持活跃。第一次调用将从磁盘加载文件,随后的调用将重新启动现有的声音。

    请注意,为了便于理解,此代码略微欠佳:它会查找 sounds[path] 两次。作为一个练习,通过在 play 调用中重用 it 来摆脱第二次查找。

    【讨论】:

    • 谢谢!我到了一半。当方法和变量在我的 Player 类中时,代码可以完美运行。但是当我将代码移动到另一个类(SoundManager)以尊重 SRP 时,它没有。我很确定这是一个指针问题,我正在处理它。如果您对此有任何建议,我很乐意,如果没有,谢谢您的帮助!
    猜你喜欢
    • 2015-03-06
    • 2022-01-15
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-05
    相关资源
    最近更新 更多