added welcome scene with text rendering using etxt

This commit is contained in:
Thomas von Dein 2024-02-14 19:35:36 +01:00
parent 48396e7e0a
commit 4f5bbdc56a
9 changed files with 159 additions and 18 deletions

Binary file not shown.

59
assets/loader-fonts.go Normal file
View File

@ -0,0 +1,59 @@
package assets
import (
"log"
"github.com/tinne26/etxt"
)
var FontRenderer = LoadFonts("fonts")
const (
GameFont string = "x12y20pxScanLine"
FontSize int = 16
)
type Texter struct {
Renderer *etxt.Renderer
}
func LoadFonts(dir string) *Texter {
fontlib := etxt.NewFontLibrary()
_, _, err := fontlib.ParseEmbedDirFonts(dir, assetfs)
if err != nil {
log.Fatalf("Error while loading fonts: %s", err.Error())
}
if !fontlib.HasFont(GameFont) {
log.Fatal("missing font: " + GameFont)
}
err = fontlib.EachFont(checkMissingRunes)
if err != nil {
log.Fatal(err)
}
renderer := etxt.NewStdRenderer()
glyphsCache := etxt.NewDefaultCache(10 * 1024 * 1024) // 10MB
renderer.SetCacheHandler(glyphsCache.NewHandler())
renderer.SetFont(fontlib.GetFont(GameFont))
return &Texter{renderer}
}
// helper function used with FontLibrary.EachFont to make sure
// all loaded fonts contain the characters or alphabet we want
func checkMissingRunes(name string, font *etxt.Font) error {
const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
const symbols = "0123456789 .,;:!?-()[]{}_&#@"
missing, err := etxt.GetMissingRunes(font, letters+symbols)
if err != nil {
return err
}
if len(missing) > 0 {
log.Fatalf("Font '%s' missing runes: %s", name, string(missing))
}
return nil
}

View File

@ -16,7 +16,7 @@ import (
// Maps image name to image data
type AssetRegistry map[string]*ebiten.Image
//go:embed levels/*.lvl sprites/*.png
//go:embed levels/*.lvl sprites/*.png fonts/*.ttf
var assetfs embed.FS
var Assets = LoadImages("sprites")

View File

@ -13,7 +13,8 @@ type Game struct {
World *ecs.World
Bounds image.Rectangle
ScreenWidth, ScreenHeight int
Scenes map[int]Scene
Scenes map[SceneName]Scene
CurrentScene SceneName
Observer *observers.GameObserver
}
@ -25,20 +26,26 @@ func NewGame(width, height, cellsize, startlevel int, startscene int) *Game {
World: &world,
ScreenWidth: width,
ScreenHeight: height,
Scenes: map[int]Scene{},
Scenes: map[SceneName]Scene{},
}
observers.NewPlayerObserver(&world)
observers.NewParticleObserver(&world)
game.Observer = observers.NewGameObserver(&world, startlevel, width, height, cellsize)
game.Scenes[Welcome] = NewWelcomeScene(game)
game.Scenes[Play] = NewLevelScene(game, startlevel)
game.CurrentScene = Welcome
fmt.Println(game.World.Stats().String())
return game
}
func (game *Game) GetCurrentScene() Scene {
return game.Scenes[game.CurrentScene]
}
func (game *Game) Update() error {
gameobserver := observers.GetGameObserver(game.World)
timer := gameobserver.StopTimer
@ -49,8 +56,12 @@ func (game *Game) Update() error {
gameobserver.Score++ // FIXME: use level.Score(), see TODO
}
for _, scene := range game.Scenes {
scene.Update()
scene := game.GetCurrentScene()
scene.Update()
next := scene.GetNext()
if next != game.CurrentScene {
game.CurrentScene = next
}
timer.Update()
@ -59,9 +70,7 @@ func (game *Game) Update() error {
}
func (game *Game) Draw(screen *ebiten.Image) {
for _, scene := range game.Scenes {
scene.Draw(screen)
}
game.GetCurrentScene().Draw(screen)
}
func (g *Game) Layout(newWidth, newHeight int) (int, int) {

View File

@ -11,14 +11,14 @@ type LevelScene struct {
Game *Game
CurrentLevel int
Levels []*Level
Next int
Whoami int
Next SceneName
Whoami SceneName
UseCache bool
}
// Implements the actual playing Scene
func NewLevelScene(game *Game, startlevel int) Scene {
scene := &LevelScene{CurrentLevel: startlevel, Whoami: Play, Game: game}
scene := &LevelScene{CurrentLevel: startlevel, Whoami: Play, Next: Play, Game: game}
scene.GenerateLevels(game)
scene.Levels[scene.CurrentLevel].SetupGrid(game)
@ -33,12 +33,13 @@ func (scene *LevelScene) GenerateLevels(game *Game) {
}
// Interface methods
func (scene *LevelScene) SetNext() int {
if scene.Whoami != scene.Next {
return scene.Next
}
func (scene *LevelScene) SetNext(next SceneName) {
scene.Next = next
}
return 0
func (scene *LevelScene) GetNext() SceneName {
// FIXME: set to winner or options screen
return scene.Next
}
func (scene *LevelScene) Update() error {

View File

@ -18,7 +18,10 @@ const (
// to render its content onto the running level, e.g. the options scene
// etc.
type Scene interface {
SetNext() int
SetNext(SceneName)
GetNext() SceneName
Update() error
Draw(screen *ebiten.Image)
}
type SceneName int

62
game/welcome_scene.go Normal file
View File

@ -0,0 +1,62 @@
package game
import (
"image/color"
"log/slog"
"openquell/assets"
"github.com/hajimehoshi/ebiten/v2"
"github.com/tinne26/etxt"
)
type WelcomeScene struct {
Game *Game
Next SceneName
Whoami SceneName
UseCache bool
}
func NewWelcomeScene(game *Game) Scene {
scene := &WelcomeScene{Whoami: Welcome, Game: game, Next: Welcome}
return scene
}
func (scene *WelcomeScene) SetNext(next SceneName) {
scene.Next = next
}
func (scene *WelcomeScene) GetNext() SceneName {
return scene.Next
}
func (scene *WelcomeScene) Update() error {
switch {
case ebiten.IsKeyPressed(ebiten.KeyEnter):
slog.Debug("welcome.Update() next")
scene.SetNext(Play)
}
return nil
}
func (scene *WelcomeScene) Draw(screen *ebiten.Image) {
screen.Clear()
op := &ebiten.DrawImageOptions{}
background := assets.Assets["background-lila"]
screen.DrawImage(background, op)
blue := color.RGBA{0, 255, 128, 255}
assets.FontRenderer.Renderer.SetTarget(screen)
assets.FontRenderer.Renderer.SetColor(blue)
assets.FontRenderer.Renderer.SetAlign(etxt.YCenter, etxt.XCenter)
assets.FontRenderer.Renderer.SetSizePx(45)
assets.FontRenderer.Renderer.Draw("Welcome to Open Quell!", 320, 200)
assets.FontRenderer.Renderer.SetAlign(etxt.Top, etxt.Left)
assets.FontRenderer.Renderer.SetSizePx(32)
assets.FontRenderer.Renderer.Draw("[press enter to start]", 100, 300)
}

4
go.mod
View File

@ -14,11 +14,13 @@ require (
github.com/jezek/xgb v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/tlinden/yadu v0.1.2 // indirect
github.com/tinne26/etxt v0.0.8 // indirect
github.com/tlinden/yadu v0.1.3 // indirect
golang.org/x/exp/shiny v0.0.0-20230817173708-d852ddb80c63 // indirect
golang.org/x/image v0.12.0 // indirect
golang.org/x/mobile v0.0.0-20230922142353-e2f452493d57 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/text v0.13.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

5
go.sum
View File

@ -15,8 +15,12 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mlange-42/arche v0.10.0 h1:fEFDAYMAnWa+xHc1oq4gVcA4PuEQOCGSRXSKITXawMw=
github.com/mlange-42/arche v0.10.0/go.mod h1:gJ5J8vBreqrf4TcBomBFPGnWdE5P3qa4LtxYHn1gDcg=
github.com/tinne26/etxt v0.0.8 h1:rjb58jkMkapRGLmhBMWnT76E/nMTXC5P1Q956BRZkoc=
github.com/tinne26/etxt v0.0.8/go.mod h1:QM/hlNkstsKC39elTFNKAR34xsMb9QoVosf+g9wlYxM=
github.com/tlinden/yadu v0.1.2 h1:TYYVnUJwziRJ9YPbIbRf9ikmDw0Q8Ifixm+J/kBQFh8=
github.com/tlinden/yadu v0.1.2/go.mod h1:l3bRmHKL9zGAR6pnBHY2HRPxBecf7L74BoBgOOpTcUA=
github.com/tlinden/yadu v0.1.3 h1:5cRCUmj+l5yvlM2irtpFBIJwVV2DPEgYSaWvF19FtcY=
github.com/tlinden/yadu v0.1.3/go.mod h1:l3bRmHKL9zGAR6pnBHY2HRPxBecf7L74BoBgOOpTcUA=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
@ -56,6 +60,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=