Adding Sound Effects (Cosplore3D Pt:20)

Chig Beef - Feb 22 - - Dev Community

Intro

This is a series following Cosplore3D, a raycaster game to learn 3D graphics. This project is part of 12 Months 12 Projects, a challenge I set myself.

Listing Sound Effects

We can't make the sound effects if we don't know what they are, so let's start listing them off.

  1. Shoot sound effect
  2. Enemy hurt sound
  3. Player hurt sound
  4. Enemy death sound
  5. Item pickup sound
  6. Trigger sound

That's a good list for now, and we can start making them.

Creating The Sound Effects

To create the sound effects, I used jsfxr, which gave me some retro sounds. You can look on the GitHub if you would like to listen to the sound effects.

Playing The Sound Effects

To play a sound we first need to load it.

if err := g.load_track("enemyDeath", "enemyDeath"); err != nil {
    return err
}
if err := g.load_track("enemyHurt", "enemyHurt"); err != nil {
    return err
}
if err := g.load_track("pickup", "pickup"); err != nil {
    return err
}
if err := g.load_track("playerHurt", "playerHurt"); err != nil {
    return err
}
if err := g.load_track("shoot", "shoot"); err != nil {
    return err
}
if err := g.load_track("trigger", "trigger"); err != nil {
    return err
}
Enter fullscreen mode Exit fullscreen mode

Yep, that's definitely Golang code. But now we should see if we can use it, let's try the shoot sound effect.

if inpututil.IsMouseButtonJustPressed(ebiten.MouseButton0) && p.weapon.curMag > 0 {
    if p.weapon.shoot(p, g.levels[p.curLevel].enemies, g.levels[p.curLevel].bosses, g.levels[p.curLevel].get_solid_tiles()) {
        g.play_audio("shoot")
    }
}
Enter fullscreen mode Exit fullscreen mode

Now if we try to run this, it not only stops the background music, but it repeatedly plays the sound effect. To fix this, we need to separate sound effects from audio. These properties are added to the Game struct.

soundEffects    map[string]*AudioPlayer
curSoundEffects []string
Enter fullscreen mode Exit fullscreen mode

Now we can load our effects into g.soundEffects.

if err := g.load_effect("enemyDeath", "enemyDeath"); err != nil {
    return err
}
if err := g.load_effect("enemyHurt", "enemyHurt"); err != nil {
    return err
}
if err := g.load_effect("pickup", "pickup"); err != nil {
    return err
}
if err := g.load_effect("playerHurt", "playerHurt"); err != nil {
    return err
}
if err := g.load_effect("shoot", "shoot"); err != nil {
    return err
}
if err := g.load_effect("trigger", "trigger"); err != nil {
    return err
}
Enter fullscreen mode Exit fullscreen mode

After a lot of messing around an creating this code, it works!

func (g *Game) play_effect(key string) {
    m, ok := g.soundEffects[g.curAudio]
    if ok {
        if m.audioPlayer.IsPlaying() {
            m.audioPlayer.Pause()
        }
    }

    m = g.soundEffects[key]

    if !slices.Contains(g.curSoundEffects, key) {
        g.curSoundEffects = append(g.curSoundEffects, key)
    }
    g.musicPlayer[key] = m

    err := g.musicPlayer[key].audioPlayer.Rewind()
    if err != nil {
        log.Fatal(err)
    }
    g.musicPlayer[key].audioPlayer.Play()
}
Enter fullscreen mode Exit fullscreen mode

Now we just need to implement this for the other sound effects. This wasn't that hard, and I was able to simply call g.player_effect(key) without any hassle.

Next

To finish off the sound element of the game, I think we should go back and look at the soundtrack, and maybe add new sound tracks for The Cosplorer and Schmeltool. This will add variety, because at the moment it just uses the same tracks. We should also redo the Ankaran sound track to fit in more.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .