Search code examples
c++audiosfml

SFML c ++ How to create a sound class for my game with ringtone functions when events occur in my game inside on include file?


In my example I could only make it work by setting everything inside the main function is confusing strange.I wish know if possible create a new class to organize all functions in on new class gamesound in one include file.if possible help

Working on main function on cpp file but i wish create a include file i think its better

      int main()
{
    //all inside main function not good confuse
    //sound play fire function
    sf::SoundBuffer fire;
    fire.loadFromFile("sounds/fire.wav");
    sf::Sound fired;
    fired.setBuffer(fire);

    // sound hit asteroid
    sf::SoundBuffer astHit;
    astHit.loadFromFile("sounds/explo_asteroid.wav");
    sf::Sound hited;
    hited.setBuffer(astHit);

    // sound Dead player
    sf::SoundBuffer pDead;
    pDead.loadFromFile("sounds/dead_player.wav");
    sf::Sound dead;
    dead.setBuffer(pDead);

    // sound Thrust Ship
    sf::SoundBuffer thrust;
    thrust.loadFromFile("sounds/thrust.wav");
    sf::Sound sthrust;
    sthrust.setBuffer(thrust);
    sthrust.setVolume(30);

     while (app.isOpen())
    {
        Event event;
        while (app.pollEvent(event))
        {
            if (event.type == Event::Closed)
                app.close();

            if (event.type == Event::KeyPressed)
             if (event.key.code == Keyboard::Space)
              {
                bullet *b = new bullet();
                b->settings(sBullet,p->x,p->y,p->angle,10);
                entities.push_back(b);
                fired.play();//fire play Sound
              }
        }

    if (Keyboard::isKeyPressed(Keyboard::Right)) p->angle+=3;
    if (Keyboard::isKeyPressed(Keyboard::Left))  p->angle-=3;
    if (Keyboard::isKeyPressed(Keyboard::Up)) p->thrust=true;
    else p->thrust=false;

    for(auto a:entities)
     for(auto b:entities)
     {
      if (a->name=="asteroid" && b->name=="bullet")
       if ( isCollide(a,b) )
           {
            hited.play();//Hited asteroid Sound
            a->life=false;
            b->life=false;

            Entity *e = new Entity();
            e->settings(sExplosion,a->x,a->y);
            e->name="explosion";
            entities.push_back(e);


            for(int i=0;i<2;i++)
            {
             if (a->R==15) continue;
             Entity *e = new asteroid();
             e->settings(sRock_small,a->x,a->y,rand()%360,15);
             entities.push_back(e);
            }

           }

      if (a->name=="player" && b->name=="asteroid")
       if ( isCollide(a,b) )
           {
            dead.play();//Dead Player Sound
            b->life=false;

            Entity *e = new Entity();
            e->settings(sExplosion_ship,a->x,a->y);
            e->name="explosion";
            entities.push_back(e);

            p->settings(sPlayer,W/2,H/2,0,20);
            p->dx=0; p->dy=0;
           }
     }


    if (p->thrust){   
        p->anim = sPlayer_go;
        sthrust.play();
    }   
    else   p->anim = sPlayer;
 }

}

Solution

  • I coded you a "proof of concept" which you should be able to build on with all the sounds that you need.

    First we'll make a header file:

    #ifndef SOUNDMANAGER
    #define SOUNDMANAGER
    
    #include <iostream>
    #include <SFML/Audio.hpp>
    
    class SoundManager {
    public:
        SoundManager();
    
        void Fire();
        void AstHit();
    
    private:
        sf::SoundBuffer sb_fire;
        sf::Sound s_fire;
        sf::SoundBuffer sb_astHit;
        sf::Sound s_astHit;
    };
    
    #endif
    

    and a cpp file:

    #include "SoundManager.h"
    
    using namespace sf;
    
    // Constructor
    SoundManager::SoundManager() {
        if (!sb_fire.loadFromFile("sounds/fire.wav")) {
            std::cout << "ERROR: sounds/fire.wav didn't load" << endl;
        } else {
            s_fire.setBuffer(sb_fire);
        }
    
        if (!sb_astHit.loadFromFile("sounds/explo_asteroid.wav")) {
            std::cout << "ERROR: sounds/explo_asteroid.wav didn't load" << endl;
        } else {
            s_astHit.setBuffer(sb_astHit);
        }
    }
    
    //Functions
    void SoundManager::Fire() {
        s_fire.play();
    }
    
    void SoundManager::AstHit() {
        s_astHit.play();
    }
    

    There are a lot of subtleties about how to build a class with it's own header, and I'm not going to go all "101 class" on you, but know this:

    • Header files (.h) contains "definitions", by which I mean class declarations, prototypes, etc.
    • Implementation files (.cpp) contains the code which goes with the definitions/prototypes/etc you put into the header file.

    Now, you can add this line to your main.cpp:

    #include "SoundManager.h" //or whatever you named it
    

    Now, in the main.cpp, where you used to declare a bunch of sounds, you can instead declare ONE instance of the SoundManager class:

    SoundManager gameSounds;
    

    When you do that, the computer creates an instance of the class we've just written. Then, it runs the Constructor, which is a function that initialize the object. If you read into this constructor, you'll see that we set up the sounds so they can be played later. The object will keep track of his own stuff, so we don't have to load something which is already loaded.

    Also, I'm the kind of guy who likes to tracks the errors in my programs, so I ninja-ed a line so when your sounds doesn't load properly it says so in your console.

    This said, now in your main() loop, whenever you want to play a sound, you can just go

    gameSounds.Fire();
    

    and the relevant sound will play. Have fun!

    (I haven't coded in cpp in a while, so if someone fresher than I spots some mistake let me know so I can edit them out for posterity.)