Sunday, February 23, 2014

How to play game voices sequentially when background music is running on iOS

I was recently hacking my way through an open-source iOS game and I was faced with two interesting problem.
  • There are multiple voices and background music that are played at different times.  It was becoming extremely difficult to hear the voices clearly when the background music was turned on.
  • To add to that, there are certain voices that needed to be played in sequence.  For example, when user reaches "Level" "n", we want to play a voice "Level" and then the level number where the user has reached.  For example, if the user has reached Level 3, we want to play "Level" and then "3" since we do not have a distinct voice for every level (may be that's not even scalable).
In this post, we will see how we fixed both this issues using a small wrapper class.

How Do They Do it?

What I ended up doing was to create a small wrapper class that had following main responsibilities:
  • Fades-out the background music to slower volume whenever a voice is playing
  • Fades-in the background music to original volume when voices have finished playing
  • Manage a queue or a playlist of voices which are played in sequence.
We made use of the CDAudioManager class its delegates to implement this class.  Once we had this class in place, it made task really simple.  The code was well encapsulated and we could use it throughout the system consistently.

Without wasting any more time, let's have a look at how actually its done!

Create the Singleton AudioManager

This class needs to act as a service to the application, hence we are going to make it a singleton class.
Initialize Fields
  • Next step is to initializes the CDAudioManager 
  • Build NSMutableArray that will hold the queue of voices for us.  
  • We will also be registering AudioManager as a delegate to the CDAudioManager class.  Hence, we will implement the protocol CDLongAudioSourceDelegate
Enqueue Voices
  • This is where we build the queue of our voices.  
  • If the audioSource is not busy playing any other voice, then we simply play the voice.  When we play the voice we will also make sure that we fade-out the background music to a lower volume.
  • Else we will add the voice to the queue of voices
Implement the Delegate
  • This is where it all comes together.
  • We implement the protocol CDLongAudioSourceDelegate, this protocol has two optional methods
    • cdAudioSourceDidFinishPlaying
    • cdAudioSourceFileDidChange
  • We are only interested in implementing the cdAudioSourceDidFinishPlaying method.  This method will be called every time CDAudioManager finishes playing a voice.
  • Every time this method is called, we know that CDAudioManager has finished playing a voice we can now play the next voice from the queue.
  • If the queue is empty, then we simply fade-in the background music to its original volume.
That's about all that we need to do!  We have successfully setup the AudioManager for voices in our game.  It will nicely play voices one after the other and fade-out the background music when the voice is playing.

For sake of completion and easy understanding, here is the full code for the class
Have some Fun!