Programmera spel i C++ för nybörjare/Ljud och musik 1

Från Wikibooks


Lägg till ljud[redigera]

Läs mer:

http://www.sfml-dev.org/tutorials/1.6/audio-sound.php

Ett spel som är helt tyst är relativt tråkigt. SFML skiljer på två olika typer av ljud: ljudeffekt och musik. Ljudeffekter är korta. En knall, fågelkvitter, rop osv. Musik används som bakgrundsljud och som kan loopas hela tiden runt, runt så länge spelet är igång.

Installation[redigera]

För att få ljud att fungera ö.h.t. måste vi se till så att SFML hittar release och debugfilerna för audio. Lägg till dem på samma sätt som du lade till andra .lib filer vid installationen av SFML. Högerklicka på projektnamnet med fet stil så att menyn kommer upp. Välj

[Properties] sedan [Linker] och under den [Input]

Ställ in alternativrutan längst upp till vänster till ”Debug” och klicka på fältet till höger om [Additional Dependencies] på höger sida. Lägg till sfml-audio-s-d.lib så att du får en lista med:

sfml-system-s-d.lib
sfml-window-s-d.lib
sfml-graphics-s-d.lib
sfml-audio-s-d.lib

Klicka på [Verkställ] knappen längst ner till höger. Ändra sedan alternativrutan överst till vänster till ”Release” och lägg till sfml-audio-s.dll till listan under ”[Additional Dependencies] på höger sida så att filnamnen är:

sfml-system-s.lib
sfml-window-s.lib
sfml-graphics-s.lib
sfml-audio-s.lib

Tryck på [OK] knappen. Nu skall det gå att spela upp ljudeffekter och bakgrundsljud i ditt spel. Du måste bara lägga till

#include <SFML/Audio.hpp>

Bland de andra include satserna i början av main.cpp.

Saknade DLL filer[redigera]

Om du t.ex. har 64 bitars versionen av Windows kommer den att klaga på att filerna openal32.dll och libsndfile-1.dll saknas. De filerna kan du hitta i

<SFML installationsbiblioteket>\ extlibs\bin\libsndfile-1.dll

För att windows skall kunna hitta filen alls kan du lägga den i

<windowsbiblioteket>\syswow64\

eller i samma mapp som projektets main.cpp ligger i.

Vill du hitta original openal32.dll kan du surfa till http://www.openal.org/ Gå till nedladdningsbiblioteket: http://connect.creativelabs.com/openal/Downloads/Forms/AllItems.aspx Ladda hem den saknade filen, troligen med länken: http://connect.creativelabs.com/openal/Downloads/oalinst.zip Kontrollera vilken av dessa två som är nyast och spara den, om du får underliga problem med ljudet.

Första ljudet[redigera]

Ta hem ett kort ljud i wav eller ogg format. Det finns en del fria ljudeffekter i ogg format att pröva med på nätet. Se här t.ex http://hamsterrepublic.com/ohrrpgce/Free_Sound_Effects.html

Döp filen till ljud.ogg och spara den i samma mapp som main.cpp så att programmet hittar den. En bit upp i koden i valfritt projekt kan du fylla i:

sf::SoundBuffer ljudtest; //skapa en ljudbuffer/hållare
if (!ljudtest.LoadFromFile("ljud.ogg")) //ladda in en fil I hållaren
{
    // Error...
}

 sf::Sound ljudeffekt; //skapa ett ljud i spelet som vi döper till ljudeffekt
ljudeffekt.SetBuffer(ljudtest); // Ladda in ljudfilens värden i ljudet så att det  går att spela upp. 
//Buffer är en sf::SoundBuffer

När du väljer olika event-typer kan du lägga in en rutin i valfritt projekt, bara för att pröva. Anta att du skall höra ljudet varje gång L-tangenten trycks ner:

if (Event.Type == sf::Event::KeyPressed) // En tangent har tryckts ner
{
if (Event.Key.Code == sf::Key::L)
{//L tangent
ljudeffekt.Play(); //spela upp ljudet
}//L tangent

Förända ljudet[redigera]

Tre enklare ändringar du kan göra med ljudfilen är:

sound.SetLoop(true);
sound.SetPitch(1.5f);
sound.SetVolume(75.f);

Om loop = true kommer ljudet att spelas upp om och om igen ända tills det uttryckligt stoppas med ett

sound.stop() ; 

Pitchen avgör hur pipigt ljudet låter och genom att ändra den kan du få variation i spelet även om du använder samma ljud. Volymen kan även den ändras litet fram och tillbaka. Volymens maxvärde är 100.0.


Ljudet kan ha tre lägen:

Sound.Play();
Sound.Pause();
Sound.Stop();

När ljudet spelats klart blir det automatiskt ett stopp, om inte loop har satts till ”true”. Om du stoppar och spelar upp samma ljud igen, eller trycker på Play() flera gånger efter varandra, börjar det att spelas upp från början. Trycker du däremot på Paus() fortsätter det från den positionen om använder Play() igen.

Ljudeffekter inuti spelloopen[redigera]

Om du vill ha många ljudeffekter inuti en spelloop måste du lägga dem i en lista och spela upp dem eftersom. Det är rätt avancerat och redan när tre ljud spelas upp samtidigt låter det otäckt bröligt. Ett enklare sätt är att kontrollera om en viss ljudeffekt håller på att spelas upp. Om så är fallet stoppas den och spelas upp från början igen. Det duger för enklare spel och du behöver bara hålla reda på ett enda ljud av en sort i spelet.

Exempelkod:[redigera]

if(ljudeffekt.GetStatus() != sf::Sound::Status::Playing)
{
   ljudeffekt.Play(); //spela upp ljudet om den inte spelas redan
   // while(ljudeffekt.GetStatus() == sf::Sound::Status::Playing) {}
 }     
else
{
  ljudeffekt.Stop(); //stoppa och påbörja ljudet igen
  ljudeffekt.Play();
  //while(ljudeffekt.GetStatus() == sf::Sound::Status::Playing) {}
}

Ibland stoppas ljudet när den händelse som startat det är färdig. Om det sker kan du tvinga ljudet att spelas klart med koden:

while(ljudeffekt.GetStatus() == sf::Sound::Status::Playing) {}

Se till så att inte Play() kommandot finns med i själva gameloopen utan att du kontrollerar om ljudet redan spelas, för om du startar uppspelningen i gameloopen startar uppspelningen om varje loopsekvens, dvs. 60 ggr i sekunden, och det enda ljud du kommer att höra är ett väsande eller ett pipljud eftersom ljudfilen bara spelar upp den första 1/60 sekunden innan den tvingas starta om igen. Om du inte startar om ljudet när ljudet redan spelas förhindras det problemet.

Musik[redigera]

Ljudfilerna laddas in helt i minnet, men det gör inte musiken. Musiken streamas in i programmet. Det gör att man kan ha i princip hur stor musikfil som helst, det påverkar inte spelets prestanda, nackdelen är att det inte går att manipulera musik lika lätt som man manipulerar ljudfiler.

Hitta en ogg låt på internet och döp den till bakgrund.ogg. SFML stöder inte mp3, men det finns mängder med gratis ogg filer att ladda hem från wikimedia commons. http://commons.wikimedia.org/wiki/Category:Ogg_files_of_music

Gratis bakgrundsmusik i mp3 format kan du hitta här: https://freemusicarchive.org/

En onlinekonverterare för mp3 till ogg kan du hitta här: http://audio.online-convert.com/convert-to-ogg

En ogg fil blir ungefär 1/3 så stor som en mp3 fil.

Man skapar först en tom musikhållare:

sf::Music bakgrundsmusik; //skapa filhållare
if (!bakgrundsmusik.OpenFromFile("musik.ogg"))//fyll hållaren med din fil
{
    // Error...
}

Spela sedan den hela tiden med

bakgrundsmusik.SetLoop(true); //få den att gå runt runt

Spela upp den när applikationen startar med

bakgrundsmusik.Play(); //spela, obs versal i Play.

Exempelkod, ljudeffekt och bakgrundsmusik:

 #include <iostream>
 #include <SFML\System.hpp>
 #include <SFML\Window.hpp>
 #include <SFML\Graphics.hpp>
 #include <SFML\Audio.hpp>


int main (int argc, char *argv)
  { //main startar
    sf::WindowSettings Settings; //skapa ett SFML fönster
    sf::Window App(sf::VideoMode(640, 480, 32), "Test av ljud", sf::Style::Close, Settings);

    //Startar spel loopen, om [ESC] används eller om man klickar på [x] ikonen
    // uppe till höger stängs programmet.

    sf::SoundBuffer ljudtest; //skapa en ljudbuffer/hållare
    if (!ljudtest.LoadFromFile("ljud.ogg")) //ladda in en fil I hållaren
        {
          // Error...
        }
 sf::Sound ljudeffekt; //skapa ett ljud i spelet som vi döper till ljudeffekt
 ljudeffekt.SetBuffer(ljudtest); // Ladda in ljudfilens värden i ljudet så att det  går att spela upp. 
 //Buffer är en sf::SoundBuffer

//Skapa musik som spelas i bakgrunden
sf::Music bakgrundsmusik; //skapa filhållare
if (!bakgrundsmusik.OpenFromFile("musik.ogg"))//fyll hållaren med din fil
   {
   // Error...
   }

 bakgrundsmusik.SetLoop(true); //få den att gå runt runt
 bakgrundsmusik.Play(); //starta bakgrundsmusiken utanför spel-loopen.

 /*************************************spel-loopen börjar ****************************/
  while (App.IsOpened())
  { //while 1 startar
   sf::Event Event; //kolla om mus/tangentbord används
 
    while (App.GetEvent(Event))
       { //while 2 börjar
       if (Event.Type == sf::Event::Closed)
           { //if 1  börjar
            App.Close();//avsluta programmet
           }//if 1 slutar

       if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
       // en tangent har tryckts ner och tangenten är escape-tangenten
           { //if 2 börjar
            App.Close();//avsluta programmet
            } //if 2 slut
       if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::L))
            {//L tangent
             ljudeffekt.Play(); //spela upp ljudet
             }//L tangent

              //Här skriver vi in vad som händer i ett spel

              //Slutligen visar vi upp ändringarna om och om igen många gånger i sekunden
              App.Display();

         } //while 2 slutar

      } //while 1 slutar


      //När alla ändringar gjorts avslutar vi programmet
      return 0;
  }

Ljud inom spelloopen, samma sorts ljud[redigera]

Om du bara skriver koden för "play" inuti spelloopen kommer du bara att höra ett oljud. Orsaken till det är att du påbörjar uppspelningen 60 ggr i sekunden utan att först stoppa det. Om du vill ha ljud i själva loopen måste du alltså kontrollera om ljudet redan spelas och om så är fallet får du stoppa ljudet för att sedan börja spela upp det igen.

kodexempel:

//Skapa ljudet som skall låta, t.ex. en explosion. Se till så att man kan höra den
// när något exploderar i spelet
sf::SoundBuffer explosionsljud; //skapa en ljudbuffer/hållare
if (!explosionsljud.LoadFromFile("kaboom.wav")) //ladda in en fil i hållaren
    {
    std::cout << "Kan inte hitta ljudfilen: kaboom.wav " << endl; 
    }
sf::Sound ljudeffekt; //skapa ett ljud i spelet som vi döper till ljudeffekt
ljudeffekt.SetBuffer(explosionsljud); // Ladda in ljudfilens värden i ljudet så att det  går att spela upp.

Längre ner, i själva loopen när något exploderar:

if(ljudeffekt.GetStatus() != sf::Sound::Status::Playing)
  {
   ljudeffekt.Play(); //spela upp ljudet om den inte spelas redan
  }     
else
  {
   ljudeffekt.Stop(); //stoppa och påbörja ljudet igen
   ljudeffekt.Play();
   }

Detta fungerar om du har samma ljud till många olika tillfällen, t.ex. många explosioner av samma typ som exploderar ungefär samtidigt på skärmen.