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, } gamearea := gamedata.Area{Width: 640, Height: 480} //initialize our layer map p.gameevents = make(map[gamedata.GameEvent]bool) //create background layer p.elements = append(p.elements, gameelement.NewBackground(gamearea)) //create canvas (game) layer canvas := gameelement.NewCanvas(gamearea) 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) canvas.RegisterEvents(gamedata.GameEventFireball, p.EventHandlerFireball) p.elements = append(p.elements, canvas) //create foreground cloud layer clouds := gameelement.NewCloudLayer(gamearea) clouds.Initialize() p.elements = append(p.elements, clouds) 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() case gamedata.GameEventFireball: player := audioContext.NewPlayerFromBytes(assets.Flare) 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 } func (p *Primary) EventHandlerFireball() { p.gameevents[gamedata.GameEventFireball] = true }