Add sound effects

This commit is contained in:
Trevor Slocum 2024-02-08 21:09:56 -08:00
parent 705217676a
commit 7a6467a498
8 changed files with 129 additions and 6 deletions

Binary file not shown.

BIN
game/asset/audio/fire.ogg Normal file

Binary file not shown.

BIN
game/asset/audio/hit.ogg Normal file

Binary file not shown.

BIN
game/asset/audio/select.ogg Normal file

Binary file not shown.

View file

@ -16,13 +16,15 @@ import (
"time"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/audio"
"github.com/hajimehoshi/ebiten/v2/audio/vorbis"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
"github.com/hajimehoshi/ebiten/v2/inpututil"
)
const screenWidth, screenHeight = 1920, 1080
const worldWidth, worldHeight = 8, 4
const worldWidth, worldHeight = 6, 2
const worldTileSize = 1536
@ -104,7 +106,48 @@ const rad = math.Pi * 2
const gamepadDeadZone = 0.2
const sampleRate = 44100
var audioContext *audio.Context
var (
Sounds [][]byte
)
type soundEffect int
const (
SoundSelect soundEffect = iota
SoundFire
SoundHit
SoundDestroy
)
func LoadBytes(p string) []byte {
b, err := assetFS.ReadFile(p)
if err != nil {
panic(err)
}
return b
}
func loadBytes(p string) []byte {
b, err := assetFS.ReadFile(p)
if err != nil {
panic(err)
}
return b
}
func loadAssets() {
audioContext = audio.NewContext(sampleRate)
p := "asset/audio/"
Sounds = append(Sounds, loadBytes(p+"select.ogg"))
Sounds = append(Sounds, loadBytes(p+"fire.ogg"))
Sounds = append(Sounds, loadBytes(p+"hit.ogg"))
Sounds = append(Sounds, loadBytes(p+"destroy.ogg"))
tankHullImages = make([]*ebiten.Image, len(tankNames))
tankTurretImages = make([]*ebiten.Image, len(tankNames))
for i, name := range tankNames {
@ -128,6 +171,28 @@ func loadAssets() {
}
}
func playSound(effect soundEffect, div float64) {
sound := Sounds[effect]
stream, err := vorbis.DecodeWithoutResampling(bytes.NewReader(sound))
if err != nil {
panic(err)
}
player, err := audioContext.NewPlayer(&oggStream{stream})
if err != nil {
panic(err)
}
volume := 0.4
switch effect {
case SoundSelect, SoundHit:
volume = 0.25
}
volume /= div
player.SetVolume(volume)
player.Play()
}
type Game struct {
sim *Simulation
treadMarks [][2]float64
@ -333,18 +398,24 @@ func (g *Game) Update() error {
if inpututil.IsKeyJustPressed(ebiten.KeyQ) {
g.size1++
} else if inpututil.IsKeyJustPressed(ebiten.KeyZ) {
go playSound(SoundSelect, 1)
} else if inpututil.IsKeyJustPressed(ebiten.KeyA) {
g.size1--
if g.size1 < 1 {
g.size1 = 1
} else {
go playSound(SoundSelect, 1)
}
}
if inpututil.IsKeyJustPressed(ebiten.KeyE) {
g.size2++
} else if inpututil.IsKeyJustPressed(ebiten.KeyC) {
go playSound(SoundSelect, 1)
} else if inpututil.IsKeyJustPressed(ebiten.KeyD) {
g.size2--
if g.size2 < 0 {
g.size2 = 0
} else {
go playSound(SoundSelect, 1)
}
}
@ -354,10 +425,13 @@ func (g *Game) Update() error {
if lastLeft >= -gamepadDeadZone && lastLeft <= gamepadDeadZone {
if g.leftStick < -gamepadDeadZone {
g.size1++
go playSound(SoundSelect, 1)
} else if g.leftStick > gamepadDeadZone {
g.size1--
if g.size1 < 1 {
g.size1 = 1
} else {
go playSound(SoundSelect, 1)
}
}
}
@ -366,10 +440,13 @@ func (g *Game) Update() error {
if lastRight >= -gamepadDeadZone && lastRight <= gamepadDeadZone {
if g.rightStick < -gamepadDeadZone {
g.size2++
go playSound(SoundSelect, 1)
} else if g.rightStick > gamepadDeadZone {
g.size2--
if g.size2 < 0 {
g.size2 = 0
} else {
go playSound(SoundSelect, 1)
}
}
}
@ -465,6 +542,7 @@ func (g *Game) Update() error {
input = input.Set(InputFire)
}
}
g.sim.SetInput(0, input)
g.setComputerInputs()
@ -606,7 +684,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
}
{
label := "ADJUST TEAM 1: Q / Z OR LEFT JOY UP / DOWN"
label := "ADJUST TEAM 1: Q / A OR LEFT JOY UP / DOWN"
w := len(label)*6 + 5
h := 15
g.scratchImage.Clear()
@ -619,7 +697,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
}
{
label := "ADJUST TEAM 2: E / C OR RIGHT JOY UP / DOWN"
label := "ADJUST TEAM 2: E / D OR RIGHT JOY UP / DOWN"
w := len(label)*6 + 5
h := 15
g.scratchImage.Clear()
@ -983,6 +1061,14 @@ func offscreen(x float64, y float64, size float64) bool {
return x < viewX-size || y < viewY-size || x >= viewX+screenWidth+size || y >= viewY+screenHeight+size
}
type oggStream struct {
*vorbis.Stream
}
func (s *oggStream) Close() error {
return nil
}
var startButtons = []ebiten.StandardGamepadButton{
ebiten.StandardGamepadButtonRightBottom,
ebiten.StandardGamepadButtonRightRight,

View file

@ -167,7 +167,7 @@ func (s *Simulation) generateMap() {
}
const treeCount = 64
{
const bufferSize = 25
const bufferSize = 125
for i := 0; i < treeCount; i++ {
TREES:
for {
@ -273,10 +273,19 @@ func (s *Simulation) tickObjects() {
r = r.Inset(10)
}
if p.In(r) {
playHitSound := func() {
div := 1.0
if offscreen(playerState.X, playerState.Y, tankSize) {
div = 10
}
go playSound(SoundHit, div)
}
switch newObject.O {
case ObjectTree:
playHitSound()
newObject.O = ObjectTreeDestroyed
case ObjectSnowman:
playHitSound()
newObject.O = ObjectSnowmanDestroyed
s.killFeed = append(s.killFeed, &killFeedEntry{
Killer: playerName(player),
@ -315,11 +324,20 @@ ROUNDS:
w /= 2
}
if p.In(image.Rect(x, y, x+w, y+h)) {
playHitSound := func() {
div := 1.0
if offscreen(state.X, state.Y, tankSize) {
div = 10
}
go playSound(SoundHit, div)
}
switch object.O {
case ObjectTree:
playHitSound()
object.O = ObjectTreeDestroyed
continue ROUNDS
case ObjectSnowman:
playHitSound()
object.O = ObjectSnowmanDestroyed
s.killFeed = append(s.killFeed, &killFeedEntry{
Killer: playerName(state.Player),
@ -339,6 +357,11 @@ ROUNDS:
if playerState.Team == state.Team || (s.godMode && player == 0) {
continue ROUNDS
}
div := 1.0
if offscreen(state.X, state.Y, tankSize) {
div = 10
}
go playSound(SoundDestroy, div)
playerState.Hit = true
s.killFeed = append(s.killFeed, &killFeedEntry{
Killer: playerName(state.Player),
@ -380,6 +403,11 @@ func (s *Simulation) tickInputs() {
if lastFire == 0 || s.offset+s.frame-lastFire >= fireCooldown {
state := s.states[s.frame][player]
if state != nil {
div := 1.0
if offscreen(state.X, state.Y, tankSize) {
div = 10
}
go playSound(SoundFire, div)
r := state.R + state.T
s.rounds[s.frame] = append(s.rounds[s.frame], &roundState{
X: state.X + float64(roundOffset)*math.Cos(r) + tankSize/2,

3
go.mod
View file

@ -5,8 +5,11 @@ go 1.21.6
require github.com/hajimehoshi/ebiten/v2 v2.6.5
require (
github.com/ebitengine/oto/v3 v3.1.0 // indirect
github.com/ebitengine/purego v0.5.2 // indirect
github.com/jezek/xgb v1.1.1 // indirect
github.com/jfreymuth/oggvorbis v1.0.5 // indirect
github.com/jfreymuth/vorbis v1.0.2 // indirect
golang.org/x/exp/shiny v0.0.0-20240205201215-2c58cdc269a3 // indirect
golang.org/x/image v0.15.0 // indirect
golang.org/x/mobile v0.0.0-20240112133503-c713f31d574b // indirect

6
go.sum
View file

@ -1,9 +1,15 @@
github.com/ebitengine/oto/v3 v3.1.0 h1:9tChG6rizyeR2w3vsygTTTVVJ9QMMyu00m2yBOCch6U=
github.com/ebitengine/oto/v3 v3.1.0/go.mod h1:IK1QTnlfZK2GIB6ziyECm433hAdTaPpOsGMLhEyEGTg=
github.com/ebitengine/purego v0.5.2 h1:r2MQEtkGzZ4LRtFZVAg5bjYKnUbxxloaeuGxH0t7qfs=
github.com/ebitengine/purego v0.5.2/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ=
github.com/hajimehoshi/ebiten/v2 v2.6.5 h1:lALv+qhEK3CBWViyiGpz4YcR6slVJEjCiS7sExKZ9OE=
github.com/hajimehoshi/ebiten/v2 v2.6.5/go.mod h1:TZtorL713an00UW4LyvMeKD8uXWnuIuCPtlH11b0pgI=
github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4=
github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
github.com/jfreymuth/oggvorbis v1.0.5 h1:u+Ck+R0eLSRhgq8WTmffYnrVtSztJcYrl588DM4e3kQ=
github.com/jfreymuth/oggvorbis v1.0.5/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII=
github.com/jfreymuth/vorbis v1.0.2 h1:m1xH6+ZI4thH927pgKD8JOH4eaGRm18rEE9/0WKjvNE=
github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ=
golang.org/x/exp/shiny v0.0.0-20240205201215-2c58cdc269a3 h1:tImqKNm/Iclm3Rqb6GffLiURSp3m1iRx/C4mturH8Ys=
golang.org/x/exp/shiny v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:3F+MieQB7dRYLTmnncoFbb1crS5lfQoTfDgQy6K4N0o=
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=