AndEngine for Android Game Development Cookbook
上QQ阅读APP看书,第一时间看更新

Introducing sounds and music

Sound and music plays a big role in gameplay for the user. If used properly, they can give a game the extra edge it needs to allow the player to become fully immersed while playing. On the other hand, they can also cause annoyance and disapproval if used incorrectly. In this recipe, we're going to jump into the subject of Sound and Music objects in AndEngine, covering the "how-to's" of loading them through to modifying their rates and more.

Getting ready

Complete the Know the life cycle recipe given in this chapter, so that we've got a basic AndEngine project set up in our IDE. Additionally, we should create a new subfolder in our project's assets/ folder. Name this folder as sfx and add a sound file named sound.mp3 and another named music.mp3. Once this is done, continue on to the How to do it... section.

How to do it…

Perform the following steps to set up a game to use the Sound and Music objects. Note that Sound objects are meant for sound effects, such as explosions, collisions, or other short audio playback events. The Music objects are meant for long audio playback events such as looping menu music or game music.

  1. The first step involves making sure that our Engine object recognizes that we plan to use Sound and Music objects in our game. Add the following lines in the onCreateEngineOptions() method of our activity's life cycle after the EngineOptions object has been created:
    engineOptions.getAudioOptions().setNeedsMusic(true);
    engineOptions.getAudioOptions().setNeedsSound(true);
  2. In step two, we will set our asset paths for the sound and music factories, then load the Sound and Music objects. Sound and Music objects are resources, so as you may have guessed, the following code can be dropped into the onCreateResources() method of our activity's life cycle:
    /* Set the base path for our SoundFactory and MusicFactory to
      * define where they will look for audio files.
     */
    SoundFactory.setAssetBasePath("sfx/");
    MusicFactory.setAssetBasePath("sfx/");
        
    // Load our "sound.mp3" file into a Sound object
    try {
      Sound mSound = SoundFactory.createSoundFromAsset(getSoundManager(), this, "sound.mp3");
    } catch (IOException e) {
      e.printStackTrace();
    }
        
    // Load our "music.mp3" file into a music object
    try {
      Music mMusic = MusicFactory.createMusicFromAsset(getMusicManager(), this, "music.mp3");
    } catch (IOException e) {
      e.printStackTrace();
    }
  3. Once the Sound objects are loaded into the SoundManager class, we can play them as we see fit by calling play() on them, be it during a collision, button click, or otherwise:
    // Play the mSound object
    mSound.play();
  4. The Music objects should be handled in a different manner to Sound objects. In cases where our Music object should loop continuously throughout the game, which is in most cases, we handle all play() and pause() methods within the activity life cycle:
    /* Music objects which loop continuously should be played in
    * onResumeGame() of the activity life cycle
    */
    @Override
    public synchronized void onResumeGame() {
      if(mMusic != null && !mMusic.isPlaying()){
        mMusic.play();
      }
      
      super.onResumeGame();
    }
    
    /* Music objects which loop continuously should be paused in
    * onPauseGame() of the activity life cycle
    */
    @Override
    public synchronized void onPauseGame() {
      if(mMusic != null && mMusic.isPlaying()){
        mMusic.pause();
      }
      
      super.onPauseGame();
    }

How it works…

In the first step for this recipe, we are required to let the Engine know whether we will be taking advantage of AndEngine's ability to play Sound or Music objects. Failing to address this step will cause an error in the application, so before we move forward in implementing audio into our game, make sure this step is done before returning EngineOptions in the onCreateEngineOptions() method.

In the second step, we are visiting the onCreateResources() method of the application's life cycle. Firstly, we are setting the base path of both SoundFactory and MusicFactory. As mentioned in the Getting ready section, we should have a folder for our audio files in the assets/sfx folder in our project, which includes all of our audio files. By calling setAssetBasePath("sfx/") on each of the two factory classes used for audio, we are now pointing to the proper folder to look for audio files. Once this is done, we can load our Sound objects through the use of the SoundFactory class and Music objects through the use of the MusicFactory class. The Sound and Music objects require us to pass the following parameters: mEngine.getSoundManager() or mEngine.getMusicManager() depending on the type of audio object we're loading, the Context class which is BaseGameActivity, or this activity, and the name of the audio file in string format.

In the third step, we can now call the play() method on the audio object that we wish to play. However, this method should only be called after the onCreateResources()callback has been notified that all resources have been loaded. To be safe, we should simply not play any Sound or Music objects until after the onCreateResources() portion of AndEngine's life cycle.

In the final step, we are setting up our Music object to call its play() method when our activity starts up and onResumeGame() is called from the life cycle. On the other end, during onPauseGame(), the Music object's pause() method is called. It is best practice in most cases to set our Music objects up this way, especially due to the eventual inevitability of application interruptions, such as phone calls or accidental pop-up clicking. This approach will allow our Music object to automatically be paused when the application leaves focus and start back up once we return from minimization, including execution.

Note

In this recipe, and others relating to resource loading, the names of the files have been hardcoded in to the code snippets. This is done to add simplicity, but it is advisable to use the strings.xml Android resource file provided for our project in order to keep strings organized and easy to manage.

There's more…

AndEngine uses Android native sound classes to provide audio entertainment within our games. These classes include a few additional methods aside from play() and pause() that allow us to have more control over the audio objects during runtime.

Music objects

The following list includes methods provided for the Music objects:

  • seekTo: The seekTo(pMilliseconds) method allows us to define where the audio playback of a specific Music object should start from. pMilliseconds is equal to the position of the audio track, in milliseconds, where we'd like to start playback upon calling play() on the Music object. In order to obtain the duration of a Music object in milliseconds, we can call mMusic.getMediaPlayer().getDuration().
  • setLooping: The setLooping(pBoolean) method simply defines whether or not the Music object should replay from the beginning once it reaches the end of its duration. If setLooping(true), the Music object will continuously repeat until the application is closed or until setLooping(false) is called.
  • setOnCompletionListener: This method allows us to apply a listener into the Music object, which gives us the opportunity to execute a function pending track completion. This is done by adding OnCompletionListener to our Music object, as follows:
    mMusic.setOnCompletionListener(new OnCompletionListener(){
      /* In the event that a Music object reaches the end of its duration,
      * the following method will be called
      */
      @Override
      public void onCompletion(MediaPlayer mp) {
      // Do something pending Music completion
      }
    });
  • setVolume: With the setVolume(pLeftVolume, pRightVolume) method, we are able to adjust the left and/or right stereo channels independently. The minimum and maximum range for volume control is equal to 0.0f for no volume and 1.0f for full volume.

Sound objects

The following list includes methods provided for the Sound objects:

  • setLooping: See the Music object's setLooping method's description above for details. Additionally, Sound objects allow us to set how many times the audio track will loop with mSound.setLoopCount(pLoopCount), where pLoopCount is an int value defining the number of times to loop.
  • setRate: The setRate(pRate) method allows us to define the rate, or speed, at which the Sound object will play, where pRate is equal to the rate as a floating point value. The default rate is equal to 1.0f, while decreasing the rate will lower the audio pitch and increasing the rate will increase audio pitch. Keep in mind, the Android API documentation states that the rate accepts values between a range of 0.5f through to 2.0f. Exceeding this range on a negative or positive scale may cause errors in playback.
  • setVolume: See the Music object's setVolume method's description above for details.

Note

For those of us who are not geared toward audio creativity, there are plenty of resources out there which are free to use. There are plenty of free sound databases that can be found online that we can use in public projects, such as http://www.soundjay.com. Keep in mind, most free-to-use databases require attribution for the files used.