Refactor to use better interfaces and event callbacks.
This commit is contained in:
@@ -62,6 +62,7 @@ func NewGame() *Game {
|
||||
musicInitialized: false,
|
||||
boss: elements.NewBoss(),
|
||||
}
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
@@ -195,6 +196,14 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
||||
op.GeoM.Translate(-MOVER_WIDTH, -MOVER_HEIGHT)
|
||||
op.GeoM.Translate(g.boss.Pos.X, g.boss.Pos.Y)
|
||||
screen.DrawImage(g.boss.Sprite, op)
|
||||
|
||||
//text.Draw(screen, fmt.Sprintf("%d", g.boss.Health), fonts.SurviveFont.Arcade, 100, 50, color.White)
|
||||
|
||||
//boss health bar
|
||||
x0 := g.boss.Pos.X - 96
|
||||
y0 := g.boss.Pos.Y - 60
|
||||
vector.DrawFilledRect(screen, float32(x0), float32(y0), 204, 12, color.Black, true)
|
||||
vector.DrawFilledRect(screen, float32(x0+2), float32(y0+2), float32(g.boss.Health)*2, 8, color.RGBA{R: 0xff, G: 0x00, B: 0x00, A: 0xff}, true)
|
||||
}
|
||||
|
||||
g.projectileMask.Clear()
|
||||
@@ -280,14 +289,15 @@ func (g *Game) StepGame() {
|
||||
//append new projectiles
|
||||
g.AppendProjectiles()
|
||||
|
||||
//add new target with increasing frequency
|
||||
g.SpawnEnemies()
|
||||
|
||||
//handle pulsewave updates
|
||||
g.HandlePulseWaveUpdate()
|
||||
|
||||
if !g.boss.Spawned && g.counter > 600 {
|
||||
g.SpawnBoss()
|
||||
if !g.boss.Spawned {
|
||||
//add new target with increasing frequency
|
||||
g.SpawnEnemies()
|
||||
if g.counter > 2000 {
|
||||
g.SpawnBoss()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -346,6 +356,20 @@ func (g *Game) HandlePulseWaveUpdate() {
|
||||
//target.SetHit()
|
||||
}
|
||||
}
|
||||
|
||||
//check for boss
|
||||
if g.boss.Spawned {
|
||||
dx := g.boss.Pos.X - g.hero.Pos.X
|
||||
dy := g.boss.Pos.Y - g.hero.Pos.Y
|
||||
r := math.Sqrt(dx*dx + dy*dy)
|
||||
|
||||
if r >= g.explosion.Radius-40 && r <= g.explosion.Radius+40 &&
|
||||
g.boss.Action <= elements.MoverActionDamaged && !g.boss.Touched {
|
||||
g.boss.ToggleColor()
|
||||
g.boss.Touched = true
|
||||
//target.SetHit()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,10 +417,10 @@ func (g *Game) UpdateProjectiles() {
|
||||
}
|
||||
}
|
||||
|
||||
//boss check first, boundary check
|
||||
//boss check: first, boundary check
|
||||
if p.Pos.X >= g.boss.Pos.X-MOVER_WIDTH && p.Pos.X <= g.boss.Pos.X+MOVER_WIDTH &&
|
||||
p.Pos.Y >= g.boss.Pos.Y-MOVER_HEIGHT && p.Pos.Y <= g.boss.Pos.Y+MOVER_HEIGHT &&
|
||||
g.boss.Action < elements.MoverActionDying {
|
||||
g.boss.Action == elements.MoverActionDamaged {
|
||||
//fmt.Println("potential collision")
|
||||
|
||||
//the following computes total collisions in the image using a projectile mask that is a duplicate of what is on screen
|
||||
@@ -476,6 +500,7 @@ func (g *Game) ResetTargetTouches() {
|
||||
for _, t := range g.targets {
|
||||
t.Touched = false
|
||||
}
|
||||
g.boss.Touched = false
|
||||
}
|
||||
|
||||
func (g *Game) AppendProjectiles() {
|
||||
@@ -636,6 +661,7 @@ func (g *Game) UpdateBoss() {
|
||||
g.boss.Update()
|
||||
|
||||
if g.boss.Action == elements.MoverActionExploding && !g.boss.SplodeInitiated {
|
||||
g.score += 10
|
||||
player := audioContext.NewPlayerFromBytes(assets.Splode)
|
||||
player.Play()
|
||||
g.boss.SplodeInitiated = true
|
||||
@@ -697,3 +723,7 @@ func (g *Game) HasCollided(mask *ebiten.Image, size int) bool {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (g *Game) SetInputs(gamedata.GameInputs) {
|
||||
|
||||
}
|
||||
|
||||
227
screens/primary.go
Normal file
227
screens/primary.go
Normal file
@@ -0,0 +1,227 @@
|
||||
package screens
|
||||
|
||||
import (
|
||||
"math"
|
||||
"mover/assets"
|
||||
"mover/gamedata"
|
||||
"mover/gameelement"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/audio"
|
||||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
)
|
||||
|
||||
type Primary struct {
|
||||
events map[ScreenManagerEvent]func()
|
||||
dimensions gamedata.Area
|
||||
elements []gameelement.GameElement
|
||||
gameevents map[gamedata.GameEvent]bool
|
||||
|
||||
paused bool
|
||||
gameover bool
|
||||
musicInitialized bool
|
||||
|
||||
audioplayer *audio.Player
|
||||
}
|
||||
|
||||
func NewPrimary() *Primary {
|
||||
p := &Primary{
|
||||
events: make(map[ScreenManagerEvent]func()),
|
||||
paused: false,
|
||||
gameover: false,
|
||||
musicInitialized: false,
|
||||
}
|
||||
|
||||
p.gameevents = make(map[gamedata.GameEvent]bool)
|
||||
|
||||
p.elements = append(p.elements, gameelement.NewBackground(gamedata.Area{Width: 640, Height: 480}))
|
||||
|
||||
canvas := gameelement.NewCanvas(gamedata.Area{Width: 640, Height: 480})
|
||||
canvas.RegisterEvents(gamedata.GameEventPlayerDeath, p.EventHandlerPlayerDeath)
|
||||
canvas.RegisterEvents(gamedata.GameEventCharge, p.EventHandlerCharge)
|
||||
canvas.RegisterEvents(gamedata.GameEventNewShot, p.EventHandlerNewShot)
|
||||
canvas.RegisterEvents(gamedata.GameEventTargetHit, p.EventHandlerTargetHit)
|
||||
canvas.RegisterEvents(gamedata.GameEventExplosion, p.EventHandlerExplosion)
|
||||
|
||||
p.elements = append(p.elements, canvas)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Primary) Update() error {
|
||||
|
||||
if !p.musicInitialized {
|
||||
s := audio.NewInfiniteLoop(assets.SoundBank[assets.MainLoop], assets.SoundBank[assets.MainLoop].Length())
|
||||
p.audioplayer, _ = audioContext.NewPlayer(s)
|
||||
p.audioplayer.Play()
|
||||
p.musicInitialized = true
|
||||
}
|
||||
|
||||
//collect all inputs
|
||||
inputs := p.CollectInputs()
|
||||
if inputs.Quit {
|
||||
p.events[EventEndgame]()
|
||||
}
|
||||
|
||||
if inputs.Reset {
|
||||
p.Reset()
|
||||
}
|
||||
|
||||
p.ProcessEventAudio()
|
||||
|
||||
if inputs.Start {
|
||||
if p.gameover {
|
||||
p.Reset()
|
||||
} else {
|
||||
p.TogglePause()
|
||||
}
|
||||
}
|
||||
|
||||
//primary game loop, for each element pass along the inputs
|
||||
//and process its update logic
|
||||
if !p.paused {
|
||||
for _, ge := range p.elements {
|
||||
ge.SetInputs(inputs)
|
||||
ge.Update()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Primary) Draw(screen *ebiten.Image) {
|
||||
//here we simply call each game elements draw function
|
||||
//as a layer on top of each other
|
||||
for _, ge := range p.elements {
|
||||
ge.Draw(screen)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Primary) SetEventHandler(e ScreenManagerEvent, f func()) {
|
||||
p.events[e] = f
|
||||
}
|
||||
|
||||
func (p *Primary) SetDimensions(a gamedata.Area) {
|
||||
p.dimensions = a
|
||||
}
|
||||
|
||||
func (p *Primary) CollectInputs() gamedata.GameInputs {
|
||||
if inpututil.IsKeyJustPressed(ebiten.KeyQ) {
|
||||
p.events[EventEndgame]()
|
||||
}
|
||||
|
||||
gi := gamedata.GameInputs{}
|
||||
|
||||
//axes
|
||||
inpx := ebiten.GamepadAxisValue(0, 0)
|
||||
inpy := ebiten.GamepadAxisValue(0, 1)
|
||||
|
||||
//handle wasd input
|
||||
if ebiten.IsKeyPressed(ebiten.KeyD) {
|
||||
inpx = 1
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyA) {
|
||||
inpx = -1
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyS) {
|
||||
inpy = 1
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyW) {
|
||||
inpy = -1
|
||||
}
|
||||
|
||||
gi.XAxis = inpx
|
||||
gi.YAxis = inpy
|
||||
|
||||
xaxis := ebiten.StandardGamepadAxisValue(0, ebiten.StandardGamepadAxisRightStickHorizontal)
|
||||
yaxis := ebiten.StandardGamepadAxisValue(0, ebiten.StandardGamepadAxisRightStickVertical)
|
||||
|
||||
if yaxis <= 0.09 && yaxis >= -0.09 {
|
||||
yaxis = 0
|
||||
}
|
||||
if xaxis <= 0.09 && xaxis >= -0.09 {
|
||||
xaxis = 0
|
||||
}
|
||||
|
||||
gi.ShotAngle = math.Atan2(yaxis, xaxis)
|
||||
|
||||
gi.Charge = inpututil.IsStandardGamepadButtonJustPressed(0, ebiten.StandardGamepadButtonRightStick)
|
||||
gi.Start = inpututil.IsStandardGamepadButtonJustPressed(0, ebiten.StandardGamepadButtonCenterRight)
|
||||
gi.Shot = ebiten.IsStandardGamepadButtonPressed(0, ebiten.StandardGamepadButtonFrontBottomRight)
|
||||
gi.Quit = inpututil.IsKeyJustPressed(ebiten.KeyQ)
|
||||
gi.Reset = inpututil.IsKeyJustPressed(ebiten.KeyR)
|
||||
|
||||
return gi
|
||||
}
|
||||
|
||||
func (p *Primary) TogglePause() {
|
||||
p.paused = !p.paused
|
||||
var player *audio.Player
|
||||
if p.paused {
|
||||
player = audioContext.NewPlayerFromBytes(assets.PauseIn)
|
||||
p.audioplayer.Pause()
|
||||
} else {
|
||||
player = audioContext.NewPlayerFromBytes(assets.PauseOut)
|
||||
p.audioplayer.Play()
|
||||
}
|
||||
player.Play()
|
||||
}
|
||||
|
||||
func (p *Primary) Reset() {
|
||||
p.paused = false
|
||||
p.gameover = false
|
||||
|
||||
for _, ge := range p.elements {
|
||||
ge.Initialize()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Primary) ProcessEventAudio() {
|
||||
for event, occurred := range p.gameevents {
|
||||
if occurred {
|
||||
p.PlayAudio(event)
|
||||
p.gameevents[event] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Primary) PlayAudio(e gamedata.GameEvent) {
|
||||
switch e {
|
||||
case gamedata.GameEventPlayerDeath:
|
||||
player := audioContext.NewPlayerFromBytes(assets.HeroDeath)
|
||||
player.Play()
|
||||
case gamedata.GameEventCharge:
|
||||
player := audioContext.NewPlayerFromBytes(assets.Magic)
|
||||
player.Play()
|
||||
case gamedata.GameEventNewShot:
|
||||
player := audioContext.NewPlayerFromBytes(assets.Shot)
|
||||
player.Play()
|
||||
case gamedata.GameEventTargetHit:
|
||||
player := audioContext.NewPlayerFromBytes(assets.TargetHit)
|
||||
player.Play()
|
||||
case gamedata.GameEventExplosion:
|
||||
player := audioContext.NewPlayerFromBytes(assets.Splode)
|
||||
player.Play()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Primary) EventHandlerPlayerDeath() {
|
||||
p.gameevents[gamedata.GameEventPlayerDeath] = true
|
||||
p.gameover = true
|
||||
}
|
||||
|
||||
func (p *Primary) EventHandlerCharge() {
|
||||
p.gameevents[gamedata.GameEventCharge] = true
|
||||
}
|
||||
|
||||
func (p *Primary) EventHandlerNewShot() {
|
||||
p.gameevents[gamedata.GameEventNewShot] = true
|
||||
}
|
||||
|
||||
func (p *Primary) EventHandlerTargetHit() {
|
||||
p.gameevents[gamedata.GameEventTargetHit] = true
|
||||
}
|
||||
|
||||
func (p *Primary) EventHandlerExplosion() {
|
||||
p.gameevents[gamedata.GameEventExplosion] = true
|
||||
}
|
||||
Reference in New Issue
Block a user