Moved initialization of textures to main (appContext).

Added info screen.
This commit is contained in:
Sander Schobers 2021-08-09 13:04:31 +02:00
parent 45b64a46ec
commit 157ec6d42d
6 changed files with 143 additions and 41 deletions

View File

@ -55,11 +55,9 @@ func (a *app) Init(ctx ui.Context) error {
ctx.Overlays().AddOnTop(fpsOverlayName, &play.FPS{Align: ui.AlignRight}, false) ctx.Overlays().AddOnTop(fpsOverlayName, &play.FPS{Align: ui.AlignRight}, false)
a.context = &appContext{ a.context = newAppContext(ctx, func(control ui.Control) {
setView: func(control ui.Control) {
a.Content = control a.Content = control
}, })
}
a.context.ShowMainMenu(ctx) a.context.ShowMainMenu(ctx)
return nil return nil

View File

@ -1,6 +1,8 @@
package main package main
import ( import (
"image"
"opslag.de/schobers/tins2021" "opslag.de/schobers/tins2021"
"opslag.de/schobers/zntg/ui" "opslag.de/schobers/zntg/ui"
) )
@ -9,6 +11,36 @@ type appContext struct {
setView func(ui.Control) setView func(ui.Control)
Debug bool Debug bool
MonsterTextureNames map[tins2021.MonsterType]string
}
func newAppContext(ctx ui.Context, setView func(ui.Control)) *appContext {
newAnimatedTexture(ctx, "star", "resources/images/star.png", func() image.Image {
return tins2021.AnimatePolygon(tins2021.CreateStar(5), tins2021.Yellow, tins2021.NewRotateAnimation(defaultAnimationFrames))
})
newAnimatedTexture(ctx, "heart", "resources/images/heart.png", func() image.Image {
return tins2021.AnimatePolygon(tins2021.CreateHeart(), tins2021.Red, tins2021.NewRotateAnimation(defaultAnimationFrames))
})
app := &appContext{
setView: setView,
MonsterTextureNames: map[tins2021.MonsterType]string{
tins2021.MonsterTypeStraight: "straight-walking-monster",
tins2021.MonsterTypeRandom: "random-walking-monster",
tins2021.MonsterTypeChaser: "chasing-monster",
},
}
newAnimatedTexture(ctx, app.MonsterTextureNames[tins2021.MonsterTypeStraight], "resources/images/monster-straight.png", func() image.Image {
return tins2021.AnimatePolygon(tins2021.CreateHexagon(), tins2021.Green, tins2021.NewWobbleAnimation(defaultAnimationFrames, 30))
})
newAnimatedTexture(ctx, app.MonsterTextureNames[tins2021.MonsterTypeRandom], "resources/images/monster-random.png", func() image.Image {
return tins2021.AnimatePolygon(tins2021.CreateHexagon(), tins2021.Blue, tins2021.NewWobbleAnimation(defaultAnimationFrames, 30))
})
newAnimatedTexture(ctx, app.MonsterTextureNames[tins2021.MonsterTypeChaser], "resources/images/monster-chaser.png", func() image.Image {
return tins2021.AnimatePolygon(tins2021.CreateHexagon(), tins2021.Purple, tins2021.NewWobbleAnimation(defaultAnimationFrames, 30))
})
return app
} }
const numberOfStars = 5 const numberOfStars = 5
@ -41,7 +73,9 @@ func (app *appContext) ShowCredits(ctx ui.Context) {
app.setView(newCredits(app, ctx)) app.setView(newCredits(app, ctx))
} }
func (app *appContext) ShowInfo(ctx ui.Context) {} func (app *appContext) ShowInfo(ctx ui.Context) {
app.setView(newInfo(app, ctx))
}
func (app *appContext) ShowMainMenu(ctx ui.Context) { func (app *appContext) ShowMainMenu(ctx ui.Context) {
app.show(newMainMenu(app, ctx)) app.show(newMainMenu(app, ctx))

89
cmd/tins2021/info.go Normal file
View File

@ -0,0 +1,89 @@
package main
import (
"opslag.de/schobers/geom"
"opslag.de/schobers/tins2021"
"opslag.de/schobers/zntg/ui"
)
type info struct {
ui.StackPanel
app *appContext
legend *ui.StackPanel
}
const infoText = "Qbitter is a game loosly based on a work \"LW305 Kringloop\" of M.C. Escher where a gnome runs down a stairs and morphs into its 2D abstract shape. The game also lends ideas from Q*Bert, a game from the eighties that was itself based on the works of M.C. Escher. In the game you (represented as a gnome) have to collect stars while trying to avoid enemies (hexagons). Every level has increasing difficulty."
type infoLegend struct {
ui.ControlBase
Icon ui.Texture
Description string
}
func (l *infoLegend) DesiredSize(ctx ui.Context, size geom.PointF32) geom.PointF32 {
return geom.PtF32(geom.NaN32(), .4*tins2021.TextureSize)
}
const infoLegenIconSize = .36
var infoLegendIconRectangle = geom.RectRelF32(0, 0, infoLegenIconSize*tins2021.TextureSize, infoLegenIconSize*tins2021.TextureSize)
func (l *infoLegend) Render(ctx ui.Context) {
bounds := l.Bounds()
separator := .3 * bounds.Dx()
textureHeight := float32(l.Icon.Height())
renderer := ctx.Renderer()
renderer.DrawTexturePointOptions(l.Icon, bounds.Min.Add2D(separator-textureHeight, 0), ui.DrawOptions{Source: &infoLegendIconRectangle})
font := ctx.Fonts().Font("score")
fontHeight := float32(font.Height())
renderer.Text(font, bounds.Min.Add2D(separator+12, .5*(textureHeight-fontHeight)), ctx.Style().Palette.Text, l.Description)
}
func newInfo(app *appContext, ctx ui.Context) ui.Control {
legend := ui.BuildStackPanel(ui.OrientationVertical, func(p *ui.StackPanel) {
p.AddChild(&infoLegend{
Icon: ctx.Textures().ScaledByName("star", infoLegenIconSize),
Description: "Collect them to complete the level.",
})
p.AddChild(&infoLegend{
Icon: ctx.Textures().ScaledByName("heart", infoLegenIconSize),
Description: "Gives (back) a life.",
})
p.AddChild(&infoLegend{
Icon: ctx.Textures().ScaledByName("straight-walking-monster", infoLegenIconSize),
Description: "Monster that walks over a fixed diagonal.",
})
p.AddChild(&infoLegend{
Icon: ctx.Textures().ScaledByName("random-walking-monster", infoLegenIconSize),
Description: "Monster that walks randomly.",
})
p.AddChild(&infoLegend{
Icon: ctx.Textures().ScaledByName("chasing-monster", infoLegenIconSize),
Description: "Monster that walks towards you.",
})
})
return Center(&info{StackPanel: ui.StackPanel{
ContainerBase: ui.ContainerBase{
Children: []ui.Control{
labelOpts("QBITTER", "title", labelOptions{TextAlignment: ui.AlignCenter}),
label("", "score"), // spacing
paragraphOpts(infoText, "score", labelOptions{TextAlignment: ui.AlignCenter}),
label("", "score"), // spacing
legend,
},
},
Orientation: ui.OrientationVertical,
}, app: app})
}
func (i *info) Handle(ctx ui.Context, e ui.Event) bool {
switch e := e.(type) {
case *ui.KeyDownEvent:
if e.Key == ui.KeyEscape || e.Key == ui.KeyEnter {
i.app.ShowMainMenu(ctx)
}
}
return i.ControlBase.Handle(ctx, e)
}

View File

@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"image"
"image/color" "image/color"
"math/rand" "math/rand"
"strconv" "strconv"
@ -24,50 +23,22 @@ type levelController struct {
Cubes cubeTexture Cubes cubeTexture
Animations map[string]*tins2021.Animations Animations map[string]*tins2021.Animations
MonsterTextureNames map[tins2021.MonsterType]string
IdleMonsters *tins2021.Animations IdleMonsters *tins2021.Animations
MovingMonsters *tins2021.Animations MovingMonsters *tins2021.Animations
SmallFont *tins2021.BitmapFont SmallFont *tins2021.BitmapFont
Font *tins2021.BitmapFont
} }
func newLevelControl(app *appContext, ctx ui.Context, level *tins2021.Level) *levelController { func newLevelControl(app *appContext, ctx ui.Context, level *tins2021.Level) *levelController {
control := &levelController{app: app} control := &levelController{app: app}
textures := ctx.Textures() textures := ctx.Textures()
control.Cubes = newCubeTexture(textures, tins2021.Orange) control.Cubes = newCubeTexture(textures, tins2021.Orange)
newAnimatedTexture(ctx, "star", "resources/images/star.png", func() image.Image {
return tins2021.AnimatePolygon(tins2021.CreateStar(5), tins2021.Yellow, tins2021.NewRotateAnimation(defaultAnimationFrames))
})
newAnimatedTexture(ctx, "heart", "resources/images/heart.png", func() image.Image {
return tins2021.AnimatePolygon(tins2021.CreateHeart(), tins2021.Red, tins2021.NewRotateAnimation(defaultAnimationFrames))
})
control.MonsterTextureNames = map[tins2021.MonsterType]string{
tins2021.MonsterTypeStraight: "straight-walking-monster",
tins2021.MonsterTypeRandom: "random-walking-monster",
tins2021.MonsterTypeChaser: "chasing-monster",
}
newAnimatedTexture(ctx, control.MonsterTextureNames[tins2021.MonsterTypeStraight], "resources/images/monster-straight.png", func() image.Image {
return tins2021.AnimatePolygon(tins2021.CreateHexagon(), tins2021.Green, tins2021.NewWobbleAnimation(defaultAnimationFrames, 30))
})
newAnimatedTexture(ctx, control.MonsterTextureNames[tins2021.MonsterTypeRandom], "resources/images/monster-random.png", func() image.Image {
return tins2021.AnimatePolygon(tins2021.CreateHexagon(), tins2021.Blue, tins2021.NewWobbleAnimation(defaultAnimationFrames, 30))
})
newAnimatedTexture(ctx, control.MonsterTextureNames[tins2021.MonsterTypeChaser], "resources/images/monster-chaser.png", func() image.Image {
return tins2021.AnimatePolygon(tins2021.CreateHexagon(), tins2021.Purple, tins2021.NewWobbleAnimation(defaultAnimationFrames, 30))
})
small, err := tins2021.NewBitmapFont(ctx.Renderer(), ctx.Fonts().Font("small"), tins2021.NumericCharacters...) small, err := tins2021.NewBitmapFont(ctx.Renderer(), ctx.Fonts().Font("small"), tins2021.NumericCharacters...)
if err != nil { if err != nil {
panic(err) panic(err)
} }
control.SmallFont = small control.SmallFont = small
font, err := tins2021.NewBitmapFont(ctx.Renderer(), ctx.Fonts().Font("default"), tins2021.AllCharacters...)
if err != nil {
panic(err)
}
control.Font = font
control.Play(level) control.Play(level)
@ -183,7 +154,7 @@ func (r *levelController) Play(level *tins2021.Level) {
for monster := range level.Monsters { for monster := range level.Monsters {
r.IdleMonsters.Frame(monster) r.IdleMonsters.Frame(monster)
} }
for _, monster := range r.MonsterTextureNames { for _, monster := range r.app.MonsterTextureNames {
r.Animations[monster] = tins2021.NewAnimations(80*time.Millisecond, defaultAnimationFrames, true, true) r.Animations[monster] = tins2021.NewAnimations(80*time.Millisecond, defaultAnimationFrames, true, true)
} }
} }
@ -228,7 +199,7 @@ func (r levelController) Render(ctx ui.Context) {
star := tins2021.NewAnimatedTexture(ctx.Textures().ScaledByName("star", scale*.4), defaultAnimationFrames) star := tins2021.NewAnimatedTexture(ctx.Textures().ScaledByName("star", scale*.4), defaultAnimationFrames)
heart := tins2021.NewAnimatedTexture(ctx.Textures().ScaledByName("heart", scale*.4), defaultAnimationFrames) heart := tins2021.NewAnimatedTexture(ctx.Textures().ScaledByName("heart", scale*.4), defaultAnimationFrames)
monsterTextures := map[tins2021.MonsterType]tins2021.AnimatedTexture{} monsterTextures := map[tins2021.MonsterType]tins2021.AnimatedTexture{}
for typ, name := range r.MonsterTextureNames { for typ, name := range r.app.MonsterTextureNames {
monsterTextures[typ] = tins2021.NewAnimatedTexture(ctx.Textures().ScaledByName(name, scale*.4), defaultAnimationFrames) monsterTextures[typ] = tins2021.NewAnimatedTexture(ctx.Textures().ScaledByName(name, scale*.4), defaultAnimationFrames)
} }
propOffset := geom.PtF32(-.5*float32(star.Texture.Height()), -.8*float32(star.Texture.Height())) propOffset := geom.PtF32(-.5*float32(star.Texture.Height()), -.8*float32(star.Texture.Height()))
@ -283,7 +254,7 @@ func (r levelController) Render(ctx ui.Context) {
continue continue
} }
_, platformPos := positionOfTile(pos, tile) _, platformPos := positionOfTile(pos, tile)
name := r.MonsterTextureNames[monsterType.Type()] name := r.app.MonsterTextureNames[monsterType.Type()]
monsterTextures[monsterType.Type()].Draw(renderer, platformPos.Add(propOffset), r.Animations[name].Frame(pos)) monsterTextures[monsterType.Type()].Draw(renderer, platformPos.Add(propOffset), r.Animations[name].Frame(pos))
} }

View File

@ -33,18 +33,21 @@ type mainMenu struct {
func newMainMenu(app *appContext, ctx ui.Context) ui.Control { func newMainMenu(app *appContext, ctx ui.Context) ui.Control {
menu := NewMenu() menu := NewMenu()
// menu.Add("Info", func(ctx ui.Context) { app.ShowInfo(ctx) }) menu.Add("Info", func(ctx ui.Context) { app.ShowInfo(ctx) })
menu.Add("Play", func(ctx ui.Context) { menu.Add("Play", func(ctx ui.Context) {
app.Play(ctx) app.Play(ctx)
}) })
menu.Add("Credits", func(ctx ui.Context) { app.ShowCredits(ctx) }) menu.Add("Credits", func(ctx ui.Context) { app.ShowCredits(ctx) })
menu.Add("Quit", func(ctx ui.Context) { ctx.Quit() }) menu.Add("Quit", func(ctx ui.Context) { ctx.Quit() })
menu.Activate(1) // play
return Center(&mainMenu{ return Center(&mainMenu{
StackPanel: ui.StackPanel{ StackPanel: ui.StackPanel{
ContainerBase: ui.ContainerBase{ ContainerBase: ui.ContainerBase{
Children: []ui.Control{ Children: []ui.Control{
label("QBITTER", "title"), label("QBITTER", "title"),
label("", "default"), // spacing
menu, menu,
}, },
}, },

View File

@ -24,3 +24,10 @@ func paragraph(text, font string) *ui.Paragraph {
l.Font.Name = font l.Font.Name = font
}) })
} }
func paragraphOpts(text, font string, opts labelOptions) *ui.Paragraph {
return ui.BuildParagraph(text, func(l *ui.Paragraph) {
l.Font.Name = font
l.TextAlignment = opts.TextAlignment
})
}