From 234a4e19a6116009bb5f5685107c9fbaca1bb879 Mon Sep 17 00:00:00 2001 From: Ray Vanderborght Date: Thu, 20 Jun 2024 22:27:40 -0700 Subject: [PATCH] Enemies spawn --- app/constants.go | 14 +++---- entity/buzzard.go | 104 +++++++++++++++++++++++++++++++++++++--------- entity/player.go | 25 ++--------- entity/sprite.go | 38 +++++++++++++++++ entity/types.go | 21 ++++++---- main.go | 23 ++++++---- 6 files changed, 160 insertions(+), 65 deletions(-) diff --git a/app/constants.go b/app/constants.go index 5fb6a30..02ca1c4 100644 --- a/app/constants.go +++ b/app/constants.go @@ -37,10 +37,10 @@ var ( time.Millisecond * time.Duration(9), } SpawnPoints = [][]int{ - {230, 90}, // right + {230, 96}, // right {132, 168}, // bottom - {109, 47}, // top - {16, 98}, // left + {109, 53}, // top + {16, 104}, // left } Controls = map[Control]ebiten.Key{ LeftButton: ebiten.KeyLeft, @@ -51,26 +51,26 @@ var ( SoundButton: ebiten.KeyS, } - White = color.NRGBA{ + White = color.RGBA{ R: 255, G: 255, B: 255, A: 255, } - Grey = color.NRGBA{ + Grey = color.RGBA{ R: 127, G: 127, B: 127, A: 255, } - Yellow = color.NRGBA{ + Yellow = color.RGBA{ R: 255, G: 255, B: 86, A: 255, } - SpawnColors = []color.NRGBA{ + SpawnColors = []color.RGBA{ White, Grey, Yellow, diff --git a/entity/buzzard.go b/entity/buzzard.go index 99a7682..e0cd948 100644 --- a/entity/buzzard.go +++ b/entity/buzzard.go @@ -1,50 +1,116 @@ package entity import ( + "github.com/depsypher/gojoust/app" + "github.com/depsypher/gojoust/assets/audio" "github.com/hajimehoshi/ebiten/v2" + "log" + "math/rand" "time" ) type Buzzard struct { - *Sprite + *MountSprite bounder *ebiten.Image lastAnimate time.Time + state PlayerState } func MakeBuzzard(ss *Sheet) *Buzzard { return &Buzzard{ - Sprite: MakeSprite(ss.Buzzard), + MountSprite: MakeMountSprite(ss.Buzzard), bounder: ss.Bounder, lastAnimate: time.Now(), } } -func (b *Buzzard) buildMount() *ebiten.Image { - image := ebiten.NewImageFromImage(b.Images[b.Frame]) - op := ebiten.DrawImageOptions{} - op.GeoM.Translate(float64(6), float64(0)) - image.DrawImage(b.bounder, &op) - return image +func (b *Buzzard) spawning(gs *GameState) { + if time.Now().Before(b.lastAnimate.Add(time.Millisecond * time.Duration(30))) { + return + } + if b.spawn <= 20 { + // emerging + b.buildSpawn(b, b.spawn) + b.spawn += 1 + if b.spawn == 20 { + if err := gs.Sounds[audio.SpawnSound].Play(gs.SoundOn); err != nil { + log.Fatal("Error playing sound", err) + } + } + } else { + b.state = MOUNTED + b.image = b.buildMount() + b.spawn = 0 + b.Vy = 1 + } + b.lastAnimate = time.Now() } -func (b *Buzzard) Draw(screen *ebiten.Image) { - s := b.Sprite - s.DrawSprite(screen) +func (b *Buzzard) buildMount() *ebiten.Image { + frame := b.Images[b.Frame] + composite := ebiten.NewImage(frame.Bounds().Dx(), frame.Bounds().Dy()) + + body := ebiten.NewImageFromImage(frame) + if b.state == SPAWNING { + col := app.SpawnColors[rand.Intn(3)] + body = b.drawSolid(composite.Bounds(), col, body) + } + // draw rider + op := ebiten.DrawImageOptions{} + y := 0 + op.GeoM.Translate(float64(4), float64(y)) + rider := ebiten.NewImageFromImage(b.bounder) + if b.state == SPAWNING { + col := app.SpawnColors[rand.Intn(3)] + rider = b.drawSolid(rider.Bounds(), col, rider) + } + composite.DrawImage(rider, &op) + op.GeoM.Reset() + composite.DrawImage(body, &op) + if !b.facingRight { + return b.flipX(composite, op) + } + return composite } -func (b *Buzzard) Update(g *GameState) { +func (b *Buzzard) mounted(gs *GameState) { if time.Now().After(b.lastAnimate.Add(time.Millisecond * time.Duration(500))) { - b.Frame += 1 + if b.Frame == 5 { + b.Frame = 6 + } else { + b.Frame = 5 + } b.lastAnimate = time.Now() } - b.Frame = (b.Frame) % len(b.Images) b.image = b.buildMount() b.X += 1 - if b.X > 300 { - b.X = float64(-b.Width) - } + b.Wrap() - b.Collisions(g.CliffAsSprites(), func(c *Sprite) { - // fmt.Printf("colliding %s\n", c.rect()) + b.Collisions(gs.CliffAsSprites(), func(c *Sprite) { + //fmt.Printf("colliding %s\n", c.rect()) }) } + +func (b *Buzzard) unmounted(gs *GameState) { +} + +func (b *Buzzard) dead(gs *GameState) { +} + +func (b *Buzzard) Draw(screen *ebiten.Image) { + s := b.Sprite + s.DrawSprite(screen) +} + +func (b *Buzzard) Update(gs *GameState) { + switch b.state { + case SPAWNING: + b.spawning(gs) + case MOUNTED: + b.mounted(gs) + case UNMOUNTED: + b.unmounted(gs) + case DEAD: + b.dead(gs) + } +} diff --git a/entity/player.go b/entity/player.go index 80cb5a5..5d7f7c0 100644 --- a/entity/player.go +++ b/entity/player.go @@ -21,28 +21,23 @@ const ( ) type Player struct { - *Sprite + *MountSprite rider *ebiten.Image lastAnimate time.Time lastAccel time.Time skid time.Time xSpeed int - walking bool - facingRight bool - spawn int - flap int walkStep bool state PlayerState } func MakePlayer(ss *Sheet) *Player { return &Player{ - Sprite: MakeSprite(ss.Ostrich), + MountSprite: MakeMountSprite(ss.Ostrich), rider: ss.P1Rider, lastAnimate: time.Now(), lastAccel: time.Now(), skid: time.Time{}, - facingRight: true, } } @@ -70,7 +65,7 @@ func (p *Player) spawning(gs *GameState) { } if p.spawn <= 20 { // emerging - p.buildSpawn(p.spawn) + p.buildSpawn(p, p.spawn) p.spawn += 1 if p.spawn == 20 { if err := gs.Sounds[audio.EnergizeSound].Play(gs.SoundOn); err != nil { @@ -347,17 +342,3 @@ func (p *Player) buildMount() *ebiten.Image { } return composite } - -func (p *Player) buildSpawn(index int) { - p.Frame = 3 - p.walking = true - mount := p.buildMount() - if p.image == nil { - p.image = ebiten.NewImage(mount.Bounds().Dx(), mount.Bounds().Dy()) - } else { - p.image.Clear() - } - op := ebiten.DrawImageOptions{} - op.GeoM.Translate(float64(0), float64(mount.Bounds().Dy()-index)) - p.image.DrawImage(mount, &op) -} diff --git a/entity/sprite.go b/entity/sprite.go index b9db0b7..acf9378 100644 --- a/entity/sprite.go +++ b/entity/sprite.go @@ -20,6 +20,10 @@ type Collider interface { Collides() } +type Mount interface { + buildMount() *ebiten.Image +} + type Sprite struct { Images []*ebiten.Image image *ebiten.Image @@ -34,6 +38,14 @@ type Sprite struct { center bool } +type MountSprite struct { + *Sprite + flap int + spawn int + walking bool + facingRight bool +} + func MakeSprite(images []*ebiten.Image, pos ...float64) *Sprite { position := []float64{0, 0} if len(pos) == 2 { @@ -50,6 +62,32 @@ func MakeSprite(images []*ebiten.Image, pos ...float64) *Sprite { } } +func MakeMountSprite(images []*ebiten.Image, pos ...float64) *MountSprite { + position := []float64{0, 0} + if len(pos) == 2 { + position = pos + } + return &MountSprite{ + Sprite: MakeSprite(images, position[0], position[1]), + flap: 0, + facingRight: true, + } +} + +func (p *MountSprite) buildSpawn(mount Mount, index int) { + p.Frame = 3 + p.walking = true + m := mount.buildMount() + if p.image == nil { + p.image = ebiten.NewImage(m.Bounds().Dx(), m.Bounds().Dy()) + } else { + p.image.Clear() + } + op := ebiten.DrawImageOptions{} + op.GeoM.Translate(float64(0), float64(m.Bounds().Dy()-index)) + p.image.DrawImage(m, &op) +} + func (s *Sprite) drawSolid(bounds image.Rectangle, color color.Color, mask image.Image) *ebiten.Image { img := ebiten.NewImage(bounds.Dx(), bounds.Dy()) img.Fill(color) diff --git a/entity/types.go b/entity/types.go index 958af08..dd59b8f 100644 --- a/entity/types.go +++ b/entity/types.go @@ -3,6 +3,7 @@ package entity import ( "github.com/depsypher/gojoust/app" "github.com/depsypher/gojoust/assets/audio" + "time" ) type GameObject interface { @@ -10,15 +11,17 @@ type GameObject interface { } type GameState struct { - Buzzards []*Buzzard - Cliffs []*Cliff - Player *Player - Keys map[app.Control]bool - GodMode bool - SoundOn bool - Pause bool - Debug string - Sounds audio.GameSounds + Buzzards []*Buzzard + Cliffs []*Cliff + Player *Player + Keys map[app.Control]bool + GodMode bool + SoundOn bool + Pause bool + Debug string + Sounds audio.GameSounds + WaveStart time.Time + NextSpawn time.Time } func (gs *GameState) CliffAsSprites() []*Sprite { diff --git a/main.go b/main.go index 424b725..0f31706 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,8 @@ import ( "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/ebitenutil" "log" + "math/rand" + "time" ) var ( @@ -35,14 +37,9 @@ func (g *Game) init() { defer func() { g.inited = true g.state = &entity.GameState{ - Keys: make(map[app.Control]bool), - GodMode: false, - } - - for i := 1; i < 2; i++ { - buzz := entity.MakeBuzzard(ss) - buzz.SetPos(app.ScreenWidth/2, app.ScreenHeight/(float64(i)+1)) - // g.state.Buzzards = append(g.state.Buzzards, buzz) + Keys: make(map[app.Control]bool), + GodMode: false, + WaveStart: time.Now(), } g.state.Player = entity.MakePlayer(ss) @@ -89,6 +86,16 @@ func (g *Game) Update() error { g.state.SoundOn = !g.state.SoundOn }) + if time.Now().After(g.state.WaveStart.Add(time.Duration(3) * time.Second)) { + if len(g.state.Buzzards) < 3 && time.Now().After(g.state.NextSpawn) { + buzz := entity.MakeBuzzard(ss) + point := app.SpawnPoints[rand.Intn(len(app.SpawnPoints))] + buzz.SetPos(float64(point[0]), float64(point[1])) + g.state.Buzzards = append(g.state.Buzzards, buzz) + g.state.NextSpawn = time.Now().Add(time.Duration(1) * time.Second) + } + } + if !g.state.Pause { g.state.Player.Update(g.state) for _, b := range g.state.Buzzards {