Added in-game menu.

This commit is contained in:
Sander Schobers 2019-12-27 13:18:33 +01:00
parent 319dc52496
commit d135139992
5 changed files with 179 additions and 31 deletions

93
alui/menu.go Normal file
View File

@ -0,0 +1,93 @@
package alui
import (
"opslag.de/schobers/allg5"
"opslag.de/schobers/geom"
)
type Menu struct {
Proxy
panel *StackPanel
active int
buttons []*Button
}
func NewMenu() *Menu {
m := &Menu{}
m.Init()
return m
}
func (m *Menu) Init() {
m.panel = &StackPanel{Orientation: OrientationVertical}
m.Proxy.Target = m.panel
}
func (m *Menu) Activate(i int) {
if len(m.buttons) == 0 || i < 0 {
return
}
m.active = i % len(m.buttons)
}
func (m *Menu) Add(text string, onClick func()) {
idx := len(m.buttons)
button := &Button{Text: text, TextAlign: allg5.AlignCenter}
button.OnClick = onClick
button.OnEnter = func() {
m.updateActiveButton(idx)
}
if idx == 0 {
button.Over = true
}
m.buttons = append(m.buttons, button)
m.panel.Children = append(m.panel.Children, button)
}
func (m *Menu) Handle(e allg5.Event) {
m.Proxy.Handle(e)
if len(m.buttons) == 0 {
return
}
switch e := e.(type) {
case *allg5.KeyCharEvent:
switch e.KeyCode {
case allg5.KeyDown:
m.updateActiveButton((m.active + 1) % len(m.buttons))
case allg5.KeyUp:
m.updateActiveButton((m.active + len(m.buttons) - 1) % len(m.buttons))
case allg5.KeyEnter:
if onClick := m.buttons[m.active].OnClick; onClick != nil {
onClick()
}
}
case *allg5.MouseMoveEvent:
for i, btn := range m.buttons {
if btn.Over {
m.updateActiveButton(i)
break
}
}
m.updateActiveButton(m.active)
}
}
func (m *Menu) Layout(ctx *Context, bounds geom.RectangleF32) {}
func (m *Menu) Render(ctx *Context, bounds geom.RectangleF32) {
menuHeight := m.Proxy.DesiredSize(ctx).Y
width, center := bounds.Dx(), bounds.Center()
menuBounds := geom.RectF32(.25*width, center.Y-.5*menuHeight, .75*width, center.Y+.5*menuHeight)
m.Proxy.Layout(ctx, menuBounds)
m.Proxy.Render(ctx, menuBounds)
}
func (m *Menu) updateActiveButton(active int) {
m.active = active
for i, btn := range m.buttons {
btn.Over = i == m.active
}
}

44
alui/proxy.go Normal file
View File

@ -0,0 +1,44 @@
package alui
import (
"opslag.de/schobers/allg5"
"opslag.de/schobers/geom"
)
var _ Control = &Proxy{}
type Proxy struct {
Target Control
}
func (p *Proxy) Bounds() geom.RectangleF32 {
if p.Target != nil {
return p.Target.Bounds()
}
return geom.RectangleF32{}
}
func (p *Proxy) DesiredSize(ctx *Context) geom.PointF32 {
if p.Target != nil {
return p.Target.DesiredSize(ctx)
}
return geom.ZeroPtF32
}
func (p *Proxy) Handle(e allg5.Event) {
if p.Target != nil {
p.Target.Handle(e)
}
}
func (p *Proxy) Render(ctx *Context, bounds geom.RectangleF32) {
if p.Target != nil {
p.Target.Render(ctx, bounds)
}
}
func (p *Proxy) Layout(ctx *Context, bounds geom.RectangleF32) {
if p.Target != nil {
p.Target.Layout(ctx, bounds)
}
}

View File

@ -25,7 +25,7 @@ func newConsole(cons *gut.Console) *console {
}
func (c *console) Render(ctx *alui.Context, bounds geom.RectangleF32) {
back := allg5.NewColorAlpha(0, 0, 0, 0x7f)
back := allg5.NewColorAlpha(0, 0, 0, 0xaf)
line := allg5.NewColor(0x7f, 0x7f, 0x7f)
c.height = geom.Min32(c.height, bounds.Dy())

View File

@ -1,41 +1,21 @@
package main
import (
"opslag.de/schobers/allg5"
"opslag.de/schobers/geom"
"opslag.de/schobers/krampus19/alui"
)
type mainMenu struct {
alui.ControlBase
alui.Menu
ctx *Context
buttons alui.StackPanel
}
func (m *mainMenu) newButton(text string, onClick func()) alui.Control {
button := &alui.Button{Text: text, TextAlign: allg5.AlignCenter}
button.OnClick = onClick
return button
}
func (m *mainMenu) Enter(ctx *Context) error {
m.ctx = ctx
m.buttons.Orientation = alui.OrientationVertical
m.buttons.Children = append(m.buttons.Children, m.newButton("Play", func() { m.ctx.Navigation.playLevel("1") }))
m.buttons.Children = append(m.buttons.Children, m.newButton("Quit", func() { m.ctx.Navigation.quit() }))
m.Init()
m.Add("Play", func() { m.ctx.Navigation.playLevel("1") })
m.Add("Quit", func() { m.ctx.Navigation.quit() })
return nil
}
func (m *mainMenu) Leave() {}
func (m *mainMenu) Handle(e allg5.Event) { m.buttons.Handle(e) }
func (m *mainMenu) Render(ctx *alui.Context, bounds geom.RectangleF32) {
buttonsHeight := m.buttons.DesiredSize(ctx).Y
width, center := bounds.Dx(), bounds.Center()
buttonsBounds := geom.RectF32(.25*width, center.Y-.5*buttonsHeight, .75*width, center.Y+.5*buttonsHeight)
m.buttons.Layout(ctx, buttonsBounds)
m.buttons.Render(ctx, buttonsBounds)
}

View File

@ -15,8 +15,12 @@ import (
type playLevel struct {
alui.ControlBase
ctx *Context
menu *alui.Menu
showMenu bool
name string
ctx *Context
offset geom.PointF32
scale float32
keysDown keyPressedState
@ -27,9 +31,8 @@ type playLevel struct {
bricks []*entity
sunken []*entity
steps int
tick time.Duration
ani gut.Animations
tick time.Duration
ani gut.Animations
}
type keyPressedState map[allg5.Key]bool
@ -168,6 +171,11 @@ func (l *playLevel) canMove(from, dir geom.Point) bool {
func (l *playLevel) Enter(ctx *Context) error {
l.ctx = ctx
l.menu = alui.NewMenu()
l.menu.Add("Resume", func() { l.showMenu = false })
l.menu.Add("Quit to main menu", func() { l.ctx.Navigation.showMainMenu() })
l.menu.Add("Quit to desktop", func() { l.ctx.Navigation.quit() })
l.keysDown = keyPressedState{}
l.level = l.ctx.Levels[l.name]
l.bricks = nil
@ -263,8 +271,28 @@ func (l *playLevel) Handle(e allg5.Event) {
switch e := e.(type) {
case *allg5.KeyDownEvent:
l.keysDown[e.KeyCode] = true
case *allg5.KeyUpEvent:
l.keysDown[e.KeyCode] = false
}
if l.showMenu {
l.menu.Handle(e)
switch e := e.(type) {
case *allg5.KeyDownEvent:
switch e.KeyCode {
case allg5.KeyEscape:
l.showMenu = false
}
}
return
}
switch e := e.(type) {
case *allg5.KeyDownEvent:
switch e.KeyCode {
case allg5.KeyEscape:
l.showMenu = true
l.menu.Activate(0)
case l.ctx.Settings.Controls.MoveUp:
l.tryPlayerMove(geom.Pt(0, -1), e.KeyCode)
case l.ctx.Settings.Controls.MoveRight:
@ -274,8 +302,6 @@ func (l *playLevel) Handle(e allg5.Event) {
case l.ctx.Settings.Controls.MoveLeft:
l.tryPlayerMove(geom.Pt(-1, 0), e.KeyCode)
}
case *allg5.KeyUpEvent:
l.keysDown[e.KeyCode] = false
}
}
@ -342,4 +368,9 @@ func (l *playLevel) Render(ctx *alui.Context, bounds geom.RectangleF32) {
font := ctx.Fonts.Get("default")
steps := fmt.Sprintf("STEPS: %d", l.steps)
ctx.Fonts.DrawAlignFont(font, bounds.Min.X, 24, bounds.Max.X, ctx.Palette.Text, allg5.AlignCenter, steps)
if l.showMenu {
allg5.DrawFilledRectangle(bounds.Min.X, bounds.Min.Y, bounds.Max.X, bounds.Max.Y, allg5.NewColorAlpha(0, 0, 0, 0xaf))
l.menu.Render(ctx, bounds)
}
}