Developing Multiplatform Game with LibGDX, part 25: SOUND! And bug fixes.

Minor tweaks

The gameplay is mostly done. One major flaw that remains is the lack of „restart”/”character selection” buttons after the game is over.

Add

eventListener.OnGameEnd(false);

function call in our GameLogic class, exactly once player’s hp reaches zero, right before GameProgress.Reset(true); call. Then modify our GameEventListener and make playerWon Boolean final.


public interface GameEventListener
{
    void OnGameEnd(final boolean playerWon);
}

Modify GameScreen’s OnGameEnd listener function to actually make use of playerWon variable. On our last action (where we get rid of the current screen. Here’s how it looks now:

new Action() {
    @Override
    public boolean act(float delta) {
        dispose();
        if (playerWon)
        {
            game.setScreen(new GameScreen(game));
        }
        else
        {
            game.setScreen(new CharacterSelectionScreen(game));
        }
        return true;
    }
}

After player gets defeated, he gets brought to CharacterSelectionScreen. That’s it. We no longer need to relaunch the game file after loss.

Few bugs:

  • Let’s Tweak our “Start” button and call GameProgress.Reset(false) before the game starts: this will ensure that player gets his max hp (in case we made an upgrade and it raised the hp).
  • After the player wins the stage – make sure to record his hp to currentLives. In our Player.markVictorious function, save the current player’s hp to GameProgress.playerLives:
public void markVictorious()
{
    winTime = timeAlive;
    winning = true;
    GameProgress.playerLives = lives;
}

Sound and Music introduction

Our final (and very important!) part is going to be about music. I’ve got two music/sound packs from opengameart.com:

Converted them to .ogg (smaller size) with http://audio.online-convert.com/convert-to-ogg tool.

I’ve converted the following files from attack sounds:

  • swing.wav -> swing0.ogg
  • swing2.wav -> swing1.ogg
  • swing3.wav -> swing2.ogg
  • coin.wav -> coin.ogg
  • bite-small.wav -> heal.ogg
  • fantozzi-sandl1 -> walk0.ogg
  • fantozzi-sandl2 -> walk1.ogg
  • Fantozzi-SandR1 -> walk2.ogg

Music is left-as is, in mp3, but renamed to music0..music5.ogg. In the directory android/assets/, create music folder and put sounds/music there. Finally, let’s get to coding! In our com.coldwild.dodginghero package, create a new class and call it SoundManager. It’s going to have static functions that controls menu music. Let’s introduce functions that load and unload sounds.

public class SoundManager {

    public static AssetManager assets = new AssetManager();

    public static void LoadSounds() {
        for (int i = 0; i < 3; i++)
        {
            assets.load(Gdx.files.internal("music/swing" + i + ".ogg").path(), Sound.class);
            assets.load(Gdx.files.internal("music/walk" + i + ".ogg").path(), Sound.class);
        }


        assets.load("music/coin.ogg", Sound.class);
        assets.load("music/heal.ogg", Sound.class);
        assets.finishLoading();
    }

    public static void ReleaseSounds()
    {
        assets.dispose();
    }


}

In our DodgingHero class, in our create function, after GameProgress.Load() call, add the call to LoadSounds function:

SoundManager.LoadSounds();

And

SoundManager.ReleaseSounds();

At the end of dispose() function. This will ensure the sounds are loaded at the start of the game and disposed at the end. The easiest ones to implement would be walk / attack sounds. Add those things to our SoundManager:

private static void playSoundRandomVolume(Sound sound, float min, float max)
{
    if (sound != null)
    {
        sound.play(MathUtils.random(min, max));
    }
}

public static void PlaySwingSound()
{
    Sound s = assets.get("music/swing" + MathUtils.random(2) + ".ogg", Sound.class);
    playSoundRandomVolume(s, 0.90f, 1.0f);
}

public static void PlayWalkSound()
{
    Sound s = assets.get("music/walk" + MathUtils.random(2) + ".ogg", Sound.class);
    playSoundRandomVolume(s, 0.45f, 0.55f);
}

Pretty straightforward: pick the necessary (random!) sound, then play it at a reasonably random volume to make it even more randomized. Put the calls to the following functions:

Character.takeDamage()

public void takeDamage(int amnt)
{
    SoundManager.PlaySwingSound();
    timeOfDmgTaken = timeAlive;
    lives -= amnt;
    if (lives < 0)
    {
        lives = 0;
    }
}

And in our GameScreen.AttemptMove

public void AttemptMove(int dx, int dy)
{
    if (player.getLives() > 0 &&
        enemy.getLives() > 0 &&
            logic.CheckMove(player.getFieldX() + dx, player.getFieldY() + dy))
    {
        logic.AssignPlayerPosition(player.getFieldX() + dx, player.getFieldY() + dy);
        SoundManager.PlayWalkSound();
    }
}

Try running the game! Whenever you move or your player gets hit – you’ll hear it. As you remember, we try to split game logic from representation. We won’t be calling soundmanager from our gamelogic, we’ll pass the bonus pickup / attack even to our gamescreen and it will handle it properly. First, add the functions for coin / health pickup:

public static void PlayCoinSound()
{
    Sound coin = assets.get("music/coin.ogg", Sound.class);
    playSoundRandomVolume(coin, 0.9f, 1.0f);
}

public static void PlayHealSound()
{
    Sound heal = assets.get("music/heal.ogg", Sound.class);
    playSoundRandomVolume(heal, 0.9f, 1.0f);
}

In our GameEventListener interface, add a new function declaration:

void OnBonusPickup(byte bonusType);

We’ll call it when player picks a bonus, in our AssignPlayerPosition, right after the check:

if (currentBonus.getFieldX() == fx &&
        currentBonus.getFieldY() == fy)
{
    eventListener.OnBonusPickup(currentBonus.getBonusType());

The only thing left for GameScreen is to implement OnBonusPickup method.

@Override
public void OnBonusPickup(byte bonusType) {
    if (bonusType == Bonus.BONUS_TYPE_COIN)
    {
        SoundManager.PlayCoinSound();
    }
    else if (bonusType == Bonus.BONUS_TYPE_HEALTH)
    {
        SoundManager.PlayHealSound();
    }
}

Run the game, hear more sounds! Awesome. That concludes this lesson. In our next lesson, we’ll work on adding music.

Relevant git commit: https://github.com/vladimirslav/dodginghero/commit/e93739a981ad6da90c2fe69bfce876ae1be045c9

Leave a Reply

Your email address will not be published. Required fields are marked *