Adding Sound Effects (Cosplore3D Pt:20)
Tags: go, gamedev, learning
Published: 2024-02-22 01:30:00

## Intro
This is a series following [Cosplore3D](https://github.com/Chig-Beef/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](https://sfxr.me/), 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.
```golang
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
}
```
Yep, that's definitely Golang code. But now we should see if we can use it, let's try the shoot sound effect.
```golang
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")
	}
}
```
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.
```golang
soundEffects    map[string]*AudioPlayer
curSoundEffects []string
```
Now we can load our effects into `g.soundEffects`.
```golang
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
}
```
After a lot of messing around an creating this code, it works!
```golang
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()
}
```
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.