openquell/game/game.go

134 lines
3.3 KiB
Go
Raw Permalink Normal View History

2024-02-06 15:26:20 +01:00
package game
import (
"fmt"
2024-02-06 15:26:20 +01:00
"image"
"log/slog"
"openquell/config"
"openquell/observers"
2024-02-06 15:26:20 +01:00
"github.com/hajimehoshi/ebiten/v2"
"github.com/mlange-42/arche/ecs"
2024-04-16 19:10:32 +02:00
input "github.com/quasilyte/ebitengine-input"
2024-02-06 15:26:20 +01:00
)
type Game struct {
World *ecs.World
Bounds image.Rectangle
ScreenWidth, ScreenHeight, Cellsize int
Scenes map[SceneName]Scene
CurrentScene SceneName
Observer *observers.GameObserver
Levels []*Level // fed in PlayScene.GenerateLevels()
Config *config.Config
2024-04-16 19:10:32 +02:00
InputSystem input.System
Input *input.Handler
2024-02-06 15:26:20 +01:00
}
func NewGame(width, height, cellsize int, cfg *config.Config, startscene SceneName) *Game {
2024-02-06 15:26:20 +01:00
world := ecs.NewWorld()
game := &Game{
Bounds: image.Rectangle{},
World: &world,
ScreenWidth: width,
ScreenHeight: height,
Scenes: map[SceneName]Scene{},
Cellsize: cellsize,
Config: cfg,
2024-02-06 15:26:20 +01:00
}
game.Observer = observers.NewGameObserver(
&world, cfg.Startlevel, width, height, cellsize)
2024-04-16 19:10:32 +02:00
game.InputSystem.Init(input.SystemConfig{
DevicesEnabled: input.AnyDevice,
})
game.Input = game.InputSystem.NewHandler(0, game.Config.Keymap)
game.Scenes[Welcome] = NewWelcomeScene(game)
2024-02-18 18:19:34 +01:00
game.Scenes[Menu] = NewMenuScene(game)
game.Scenes[About] = NewAboutScene(game)
2024-02-18 18:19:34 +01:00
game.Scenes[Popup] = NewPopupScene(game)
game.Scenes[Play] = NewPlayScene(game, cfg.Startlevel)
2024-02-18 18:19:34 +01:00
game.Scenes[Select] = NewSelectScene(game)
game.CurrentScene = startscene
fmt.Println(game.World.Stats().String())
2024-02-06 15:26:20 +01:00
return game
}
func (game *Game) GetCurrentScene() Scene {
return game.Scenes[game.CurrentScene]
}
2024-02-06 15:26:20 +01:00
func (game *Game) Update() error {
2024-04-16 19:10:32 +02:00
// update ebitengine-input
game.InputSystem.Update()
2024-02-18 18:19:34 +01:00
// handle level ends
timer := game.Observer.StopTimer
if timer.IsReady() {
// a level is either lost or won, we display a small popup
// asking the user how to continue from here
timer.Reset()
slog.Debug("timer ready", "lost", game.Observer.Lost, "retry", game.Observer.Retry)
game.Observer.AddScore()
game.Scenes[Nextlevel] = NewNextlevelScene(game)
game.CurrentScene = Nextlevel
}
scene := game.GetCurrentScene()
scene.Update()
2024-02-18 18:19:34 +01:00
if scene.Clearscreen() {
ebiten.SetScreenClearedEveryFrame(true)
} else {
ebiten.SetScreenClearedEveryFrame(false)
}
next := scene.GetNext()
if next != game.CurrentScene {
if next == Play && game.CurrentScene == Nextlevel {
// switched from nextlevel (lost or won) popup to play (either retry or next level)
if !game.Observer.Retry {
game.Observer.CurrentLevel++
}
game.Observer.Retry = false
}
if next == Play {
// fresh setup of actual level every time we enter the play scene
game.Scenes[Play].SetLevel(game.Observer.CurrentLevel)
}
// make sure we stay on the selected scene
scene.ResetNext()
// finally switch
game.CurrentScene = next
// FIXME: add some reset function to game.Observer for these kinds of things
game.Observer.Lost = false
2024-02-06 15:26:20 +01:00
}
timer.Update()
2024-02-06 15:26:20 +01:00
return nil
}
func (game *Game) Draw(screen *ebiten.Image) {
game.GetCurrentScene().Draw(screen)
2024-02-06 15:26:20 +01:00
}
func (g *Game) Layout(newWidth, newHeight int) (int, int) {
return g.ScreenWidth, g.ScreenHeight
}