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.
- Shoot sound effect
- Enemy hurt sound
- Player hurt sound
- Enemy death sound
- Item pickup sound
- 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
}
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")
}
}
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
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
}
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()
}
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.