package game import ( "fmt" "os" "strings" "github.com/hajimehoshi/ebiten/v2/inpututil" "code.rocketnine.space/tslocum/doctorlectro/asset" "code.rocketnine.space/tslocum/doctorlectro/entity" "code.rocketnine.space/tslocum/doctorlectro/level" "code.rocketnine.space/tslocum/doctorlectro/system" "code.rocketnine.space/tslocum/doctorlectro/world" "code.rocketnine.space/tslocum/gohan" "github.com/hajimehoshi/ebiten/v2" "github.com/jakecoffman/cp" ) const introMessage = ` DOCTOR LECTRO, THE MAD SCIENTIST, HAS TAKEN CHARGE OF EARTH'S MAGNETIC POLES! ANIMALS, ELECTRONICS, AND HAIRSTYLES ACROSS THE GLOBE ARE IN GRAVE DANGER! STOP DOCTOR LECTRO BEFORE IT IS TOO LATE! ` type Game struct { shownIntro bool } func NewGame() (*Game, error) { g := &Game{} g.reset() g.addSystems() return g, nil } // addSystems adds all systems to the game. Systems run in the order they are // added in. Systems do not run in parallel. func (g *Game) addSystems() { gohan.AddSystem(system.NewPhysicsSystem()) gohan.AddSystem(system.NewPlayerMoveSystem()) gohan.AddSystem(system.NewMovementSystem()) for layer := world.LayerPlatform; layer <= world.LayerDefault; layer++ { gohan.AddSystem(system.NewRenderSystem(layer)) } gohan.AddSystem(system.NewRenderMessageSystem()) gohan.AddSystem(system.NewWinSystem()) gohan.AddSystem(system.NewRenderDebugTextSystem()) } func (g *Game) reset() { for _, e := range gohan.AllEntities() { e.Remove() } world.GameOver = false world.Tick = 0 world.CanJump = false world.CanMagnetize = false world.CanFire = false world.CanDoubleJump = false world.LastFire = 0 world.MetalRects = nil world.HazardRects = nil world.Clinging = false world.LastWalkDirL = true world.LastWalkDirU = true world.Space = cp.NewSpace() world.Space.Iterations = 1 world.Space.SetGravity(cp.Vector{0, world.Gravity}) world.Player = entity.NewPlayer() level.LoadMap() if world.Give != "" { for _, ability := range strings.Split(world.Give, ",") { switch strings.ToLower(ability) { case "jump": world.CanJump = true case "magnetize": world.CanMagnetize = true case "fire": world.CanFire = true case "switch": world.CanDoubleJump = true default: panic(fmt.Sprintf("unknown ability to give player: %s", ability)) } } } } func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) { return world.ScreenWidth, world.ScreenHeight } func (g *Game) Update() error { if ebiten.IsWindowBeingClosed() { g.Exit() return nil } if world.ResetGame { g.reset() world.ResetGame = false } if inpututil.IsKeyJustPressed(ebiten.KeyM) { if asset.SoundMusic.IsPlaying() { asset.SoundMusic.Pause() } else { asset.SoundMusic.Play() } } if world.MessageText != "" { if ebiten.IsKeyPressed(ebiten.KeyEnter) { world.MessageText = "" } return nil } if !world.ShownIntro && world.Tick == 0 { world.SetMessage(strings.TrimSpace(introMessage)) world.ShownIntro = true if !world.StartMuted { asset.SoundMusic.Play() } } return gohan.Update() } func (g *Game) Draw(screen *ebiten.Image) { err := gohan.Draw(screen) if err != nil { panic(err) } } func (g *Game) Exit() { os.Exit(0) }