doctorlectro/game/game.go

156 lines
3.1 KiB
Go

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.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 "doublejump":
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 !g.shownIntro && world.Tick == 0 {
world.SetMessage(strings.TrimSpace(introMessage))
g.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)
}