Added in-game menu.
This commit is contained in:
parent
319dc52496
commit
d135139992
93
alui/menu.go
Normal file
93
alui/menu.go
Normal 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
44
alui/proxy.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,7 @@ func newConsole(cons *gut.Console) *console {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *console) Render(ctx *alui.Context, bounds geom.RectangleF32) {
|
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)
|
line := allg5.NewColor(0x7f, 0x7f, 0x7f)
|
||||||
|
|
||||||
c.height = geom.Min32(c.height, bounds.Dy())
|
c.height = geom.Min32(c.height, bounds.Dy())
|
||||||
|
@ -1,41 +1,21 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"opslag.de/schobers/allg5"
|
|
||||||
"opslag.de/schobers/geom"
|
|
||||||
"opslag.de/schobers/krampus19/alui"
|
"opslag.de/schobers/krampus19/alui"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mainMenu struct {
|
type mainMenu struct {
|
||||||
alui.ControlBase
|
alui.Menu
|
||||||
|
|
||||||
ctx *Context
|
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 {
|
func (m *mainMenu) Enter(ctx *Context) error {
|
||||||
m.ctx = ctx
|
m.ctx = ctx
|
||||||
m.buttons.Orientation = alui.OrientationVertical
|
m.Init()
|
||||||
m.buttons.Children = append(m.buttons.Children, m.newButton("Play", func() { m.ctx.Navigation.playLevel("1") }))
|
m.Add("Play", func() { m.ctx.Navigation.playLevel("1") })
|
||||||
m.buttons.Children = append(m.buttons.Children, m.newButton("Quit", func() { m.ctx.Navigation.quit() }))
|
m.Add("Quit", func() { m.ctx.Navigation.quit() })
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mainMenu) Leave() {}
|
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)
|
|
||||||
}
|
|
||||||
|
@ -15,8 +15,12 @@ import (
|
|||||||
type playLevel struct {
|
type playLevel struct {
|
||||||
alui.ControlBase
|
alui.ControlBase
|
||||||
|
|
||||||
|
ctx *Context
|
||||||
|
|
||||||
|
menu *alui.Menu
|
||||||
|
showMenu bool
|
||||||
|
|
||||||
name string
|
name string
|
||||||
ctx *Context
|
|
||||||
offset geom.PointF32
|
offset geom.PointF32
|
||||||
scale float32
|
scale float32
|
||||||
keysDown keyPressedState
|
keysDown keyPressedState
|
||||||
@ -27,9 +31,8 @@ type playLevel struct {
|
|||||||
bricks []*entity
|
bricks []*entity
|
||||||
sunken []*entity
|
sunken []*entity
|
||||||
steps int
|
steps int
|
||||||
|
tick time.Duration
|
||||||
tick time.Duration
|
ani gut.Animations
|
||||||
ani gut.Animations
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type keyPressedState map[allg5.Key]bool
|
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 {
|
func (l *playLevel) Enter(ctx *Context) error {
|
||||||
l.ctx = ctx
|
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.keysDown = keyPressedState{}
|
||||||
l.level = l.ctx.Levels[l.name]
|
l.level = l.ctx.Levels[l.name]
|
||||||
l.bricks = nil
|
l.bricks = nil
|
||||||
@ -263,8 +271,28 @@ func (l *playLevel) Handle(e allg5.Event) {
|
|||||||
switch e := e.(type) {
|
switch e := e.(type) {
|
||||||
case *allg5.KeyDownEvent:
|
case *allg5.KeyDownEvent:
|
||||||
l.keysDown[e.KeyCode] = true
|
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 {
|
switch e.KeyCode {
|
||||||
|
case allg5.KeyEscape:
|
||||||
|
l.showMenu = true
|
||||||
|
l.menu.Activate(0)
|
||||||
case l.ctx.Settings.Controls.MoveUp:
|
case l.ctx.Settings.Controls.MoveUp:
|
||||||
l.tryPlayerMove(geom.Pt(0, -1), e.KeyCode)
|
l.tryPlayerMove(geom.Pt(0, -1), e.KeyCode)
|
||||||
case l.ctx.Settings.Controls.MoveRight:
|
case l.ctx.Settings.Controls.MoveRight:
|
||||||
@ -274,8 +302,6 @@ func (l *playLevel) Handle(e allg5.Event) {
|
|||||||
case l.ctx.Settings.Controls.MoveLeft:
|
case l.ctx.Settings.Controls.MoveLeft:
|
||||||
l.tryPlayerMove(geom.Pt(-1, 0), e.KeyCode)
|
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")
|
font := ctx.Fonts.Get("default")
|
||||||
steps := fmt.Sprintf("STEPS: %d", l.steps)
|
steps := fmt.Sprintf("STEPS: %d", l.steps)
|
||||||
ctx.Fonts.DrawAlignFont(font, bounds.Min.X, 24, bounds.Max.X, ctx.Palette.Text, allg5.AlignCenter, 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user