Fixed Research dialog.
This commit is contained in:
parent
28ab816bae
commit
89c8a5225e
137
dial.go
Normal file
137
dial.go
Normal file
@ -0,0 +1,137 @@
|
||||
package tins2020
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"opslag.de/schobers/geom"
|
||||
"opslag.de/schobers/zntg/ui"
|
||||
)
|
||||
|
||||
type Dial struct {
|
||||
ui.ContainerBase
|
||||
|
||||
dialer Dialer
|
||||
|
||||
typing string // current digit
|
||||
digitCount int // number of times the digit is pressed
|
||||
digits []DialDigit // digits
|
||||
}
|
||||
|
||||
func NewDial(dialer Dialer) *Dial {
|
||||
dial := &Dial{dialer: dialer}
|
||||
dial.digits = make([]DialDigit, 10)
|
||||
|
||||
for i := range dial.digits {
|
||||
j := i
|
||||
dial.digits[i].Value = strconv.Itoa(i)
|
||||
dial.digits[i].ControlClicked().AddHandler(func(ctx ui.Context, _ ui.ControlClickedArgs) {
|
||||
dial.userTyped(ctx, j)
|
||||
})
|
||||
dial.AddChild(&dial.digits[i])
|
||||
}
|
||||
return dial
|
||||
}
|
||||
|
||||
func (d *Dial) userTyped(ctx ui.Context, i int) {
|
||||
d.digits[i].Blink()
|
||||
digit := strconv.Itoa(i)
|
||||
if len(d.typing) == 0 || digit != d.typing {
|
||||
d.typing = digit
|
||||
d.digitCount = 1
|
||||
} else {
|
||||
d.digitCount++
|
||||
}
|
||||
|
||||
if !d.dialer.CanUserType(i) {
|
||||
d.typing = ""
|
||||
d.digitCount = 0
|
||||
d.dialer.UserGaveWrongInput()
|
||||
} else if d.digitCount == i || d.digitCount == 10 {
|
||||
d.typing = ""
|
||||
d.digitCount = 0
|
||||
d.dialer.UserTyped(ctx, i)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dial) Arrange(ctx ui.Context, bounds geom.RectangleF32, offset geom.PointF32, parent ui.Control) {
|
||||
d.ControlBase.Arrange(ctx, bounds, offset, parent)
|
||||
|
||||
center := bounds.Center()
|
||||
size := bounds.Size()
|
||||
|
||||
distance := size.Y * .3
|
||||
for i := range d.digits {
|
||||
angle := (float32((10-i)%10)*0.16 + .2) * math.Pi
|
||||
pos := geom.PtF32(distance*geom.Cos32(angle), .8*distance*geom.Sin32(angle))
|
||||
digitCenter := center.Add(pos)
|
||||
d.digits[i].Arrange(ctx, geom.RectRelF32(digitCenter.X-24, digitCenter.Y-24, 48, 48), offset, d)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dial) DesiredSize(ctx ui.Context, size geom.PointF32) geom.PointF32 {
|
||||
return geom.PtF32(size.X, geom.NaN32())
|
||||
}
|
||||
|
||||
func (d *Dial) Handle(ctx ui.Context, event ui.Event) bool {
|
||||
if d.ContainerBase.Handle(ctx, event) {
|
||||
return true
|
||||
}
|
||||
switch e := event.(type) {
|
||||
case *ui.KeyDownEvent:
|
||||
switch e.Key {
|
||||
case ui.Key0:
|
||||
d.userTyped(ctx, 0)
|
||||
case ui.KeyPad0:
|
||||
d.userTyped(ctx, 0)
|
||||
case ui.Key1:
|
||||
d.userTyped(ctx, 1)
|
||||
case ui.KeyPad1:
|
||||
d.userTyped(ctx, 1)
|
||||
case ui.Key2:
|
||||
d.userTyped(ctx, 2)
|
||||
case ui.KeyPad2:
|
||||
d.userTyped(ctx, 2)
|
||||
case ui.Key3:
|
||||
d.userTyped(ctx, 3)
|
||||
case ui.KeyPad3:
|
||||
d.userTyped(ctx, 3)
|
||||
case ui.Key4:
|
||||
d.userTyped(ctx, 4)
|
||||
case ui.KeyPad4:
|
||||
d.userTyped(ctx, 4)
|
||||
case ui.Key5:
|
||||
d.userTyped(ctx, 5)
|
||||
case ui.KeyPad5:
|
||||
d.userTyped(ctx, 5)
|
||||
case ui.Key6:
|
||||
d.userTyped(ctx, 6)
|
||||
case ui.KeyPad6:
|
||||
d.userTyped(ctx, 6)
|
||||
case ui.Key7:
|
||||
d.userTyped(ctx, 7)
|
||||
case ui.KeyPad7:
|
||||
d.userTyped(ctx, 7)
|
||||
case ui.Key8:
|
||||
d.userTyped(ctx, 8)
|
||||
case ui.KeyPad8:
|
||||
d.userTyped(ctx, 8)
|
||||
case ui.Key9:
|
||||
d.userTyped(ctx, 9)
|
||||
case ui.KeyPad9:
|
||||
d.userTyped(ctx, 9)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (d *Dial) Reset() {
|
||||
d.typing = ""
|
||||
d.digitCount = 0
|
||||
}
|
||||
|
||||
func (d *Dial) Tick() {
|
||||
for i := range d.digits {
|
||||
d.digits[i].Tick()
|
||||
}
|
||||
}
|
34
dialdigit.go
Normal file
34
dialdigit.go
Normal file
@ -0,0 +1,34 @@
|
||||
package tins2020
|
||||
|
||||
import (
|
||||
"opslag.de/schobers/geom"
|
||||
"opslag.de/schobers/zntg"
|
||||
"opslag.de/schobers/zntg/ui"
|
||||
)
|
||||
|
||||
type DialDigit struct {
|
||||
ui.ControlBase
|
||||
|
||||
Value string
|
||||
|
||||
highlight int
|
||||
}
|
||||
|
||||
func (d *DialDigit) Blink() {
|
||||
d.highlight = 4
|
||||
}
|
||||
|
||||
func (d *DialDigit) Render(ctx ui.Context) {
|
||||
color := zntg.MustHexColor(`#FFFFFF`)
|
||||
if d.highlight > 0 {
|
||||
color = zntg.MustHexColor(`#15569F`)
|
||||
}
|
||||
bounds := d.Bounds()
|
||||
ctx.Fonts().TextAlign("title", geom.PtF32(bounds.Center().X, bounds.Min.Y), color, d.Value, ui.AlignCenter)
|
||||
}
|
||||
|
||||
func (d *DialDigit) Tick() {
|
||||
if d.highlight > 0 {
|
||||
d.highlight--
|
||||
}
|
||||
}
|
14
dialogs.go
14
dialogs.go
@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
type Dialogs struct {
|
||||
ui.OverlayProxy
|
||||
ui.Proxy
|
||||
|
||||
intro ui.Overlay
|
||||
research ui.Overlay
|
||||
@ -21,7 +21,7 @@ const dialogsOverlayName = "dialogs"
|
||||
func NewDialogs(game *Game) *Dialogs {
|
||||
intro := NewIntro()
|
||||
research := NewResearch(game)
|
||||
settings := NewLargeDialog("settings", &ui.Label{})
|
||||
settings := NewLargeDialog("Settings", &ui.Label{})
|
||||
|
||||
dialogs := &Dialogs{
|
||||
intro: intro,
|
||||
@ -46,9 +46,9 @@ func (d *Dialogs) Init(ctx ui.Context) {
|
||||
|
||||
func (d *Dialogs) showDialog(ctx ui.Context, control ui.Control) {
|
||||
if control == nil {
|
||||
d.Content = d.nothing
|
||||
ctx.Overlays().Hide(dialogsOverlayName)
|
||||
d.closed.Notify(ctx, control)
|
||||
d.Content = d.nothing
|
||||
} else {
|
||||
d.Content = control
|
||||
ctx.Overlays().Show(dialogsOverlayName)
|
||||
@ -63,10 +63,18 @@ func (d *Dialogs) Close(ctx ui.Context) {
|
||||
func (d *Dialogs) DialogClosed() ui.EventHandler { return &d.closed }
|
||||
func (d *Dialogs) DialogOpened() ui.EventHandler { return &d.opened }
|
||||
|
||||
func (d *Dialogs) Hidden() {
|
||||
d.Proxy.Hidden()
|
||||
}
|
||||
|
||||
func (d *Dialogs) ShowIntro(ctx ui.Context) {
|
||||
d.showDialog(ctx, d.intro)
|
||||
}
|
||||
|
||||
func (d *Dialogs) Shown() {
|
||||
d.Proxy.Shown()
|
||||
}
|
||||
|
||||
func (d *Dialogs) ShowResearch(ctx ui.Context) {
|
||||
d.showDialog(ctx, d.research)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ type LargeDialog struct {
|
||||
ui.StackPanel
|
||||
|
||||
titleBar *LargeDialogTitleBar
|
||||
content ui.OverlayProxy
|
||||
content ui.Proxy
|
||||
|
||||
closeRequested ui.Events
|
||||
}
|
||||
|
188
research.go
188
research.go
@ -2,7 +2,6 @@ package tins2020
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -15,185 +14,68 @@ import (
|
||||
)
|
||||
|
||||
type Research struct {
|
||||
ui.ContainerBase
|
||||
ui.StackPanel
|
||||
|
||||
game *Game
|
||||
botanist Specialist
|
||||
farmer Specialist
|
||||
|
||||
typing string
|
||||
digitCount int
|
||||
|
||||
close func()
|
||||
description ui.Paragraph
|
||||
specialists ui.Paragraph
|
||||
dial *Dial
|
||||
input ui.Label
|
||||
digits []Digit
|
||||
|
||||
animate zntg.Animation
|
||||
closeRequested ui.Events
|
||||
}
|
||||
|
||||
type Dialer interface {
|
||||
CanUserType(int) bool
|
||||
UserGaveWrongInput()
|
||||
UserTyped(ui.Context, int)
|
||||
}
|
||||
|
||||
func NewResearch(game *Game) *LargeDialog {
|
||||
research := &Research{game: game}
|
||||
research.animate.Interval = 20 * time.Millisecond
|
||||
|
||||
research.Children = []ui.Control{&research.description, &research.specialists, &research.input}
|
||||
research.animate.Start()
|
||||
|
||||
research.description.Text = "Call a specialist to conduct research with."
|
||||
research.digits = make([]Digit, 10)
|
||||
for i := range research.digits {
|
||||
j := i
|
||||
research.digits[i].Value = strconv.Itoa(i)
|
||||
research.digits[i].ControlClicked().AddHandler(func(ctx ui.Context, _ ui.ControlClickedArgs) {
|
||||
research.userTyped(ctx, j)
|
||||
})
|
||||
research.AddChild(&research.digits[i])
|
||||
}
|
||||
dialog := NewLargeDialog("Research", research)
|
||||
// dialog.OnShow().RegisterItf(func(state interface{}) {
|
||||
// research.onShow(state.(ui.Context))
|
||||
// })
|
||||
// research.close = func() { dialog.CloseDialog() }
|
||||
research.dial = NewDial(research)
|
||||
research.Children = []ui.Control{&research.description, &research.specialists, research.dial, &research.input}
|
||||
|
||||
dialog := NewLargeDialog("Research", ui.Stretch(research))
|
||||
research.closeRequested.AddHandlerEmpty(func(ctx ui.Context) { dialog.closeRequested.Notify(ctx, nil) })
|
||||
return dialog
|
||||
}
|
||||
|
||||
type Digit struct {
|
||||
ui.ControlBase
|
||||
|
||||
Value string
|
||||
|
||||
highlight int
|
||||
}
|
||||
|
||||
func (d *Digit) Blink() {
|
||||
d.highlight = 4
|
||||
}
|
||||
|
||||
func (d *Digit) Render(ctx ui.Context) {
|
||||
color := zntg.MustHexColor(`#FFFFFF`)
|
||||
if d.highlight > 0 {
|
||||
color = zntg.MustHexColor(`#15569F`)
|
||||
}
|
||||
bounds := d.Bounds()
|
||||
ctx.Fonts().TextAlign("title", geom.PtF32(bounds.Center().X, bounds.Min.Y), color, d.Value, ui.AlignCenter)
|
||||
}
|
||||
|
||||
func (d *Digit) Tick() {
|
||||
if d.highlight > 0 {
|
||||
d.highlight--
|
||||
}
|
||||
}
|
||||
|
||||
type Specialist struct {
|
||||
Cost int
|
||||
Number string
|
||||
}
|
||||
|
||||
func (r *Research) Arrange(ctx ui.Context, bounds geom.RectangleF32, offset geom.PointF32, parent ui.Control) {
|
||||
r.ContainerBase.Arrange(ctx, bounds, offset, parent)
|
||||
|
||||
size := bounds.Size()
|
||||
r.specialists.Arrange(ctx, geom.RectRelF32(bounds.Min.X, bounds.Min.Y+40, size.X, size.Y-40), offset, r)
|
||||
r.input.Arrange(ctx, geom.RectRelF32(bounds.Min.X, bounds.Min.X+size.Y-48, size.X, 24), offset, r)
|
||||
r.input.TextAlignment = ui.AlignCenter
|
||||
r.StackPanel.Arrange(ctx, bounds, offset, parent)
|
||||
|
||||
center := bounds.Center()
|
||||
|
||||
distance := size.Y * .3
|
||||
for i := range r.digits {
|
||||
angle := (float32((10-i)%10)*0.16 + .2) * math.Pi
|
||||
pos := geom.PtF32(distance*geom.Cos32(angle), .8*distance*geom.Sin32(angle))
|
||||
digitCenter := center.Add(pos)
|
||||
r.digits[i].Arrange(ctx, geom.RectRelF32(digitCenter.X-24, digitCenter.Y-24, 48, 48), offset, r)
|
||||
}
|
||||
// size := bounds.Size()
|
||||
// r.specialists.Arrange(ctx, geom.RectRelF32(bounds.Min.X, bounds.Min.Y+40, size.X, size.Y-40), offset, r)
|
||||
// r.input.Arrange(ctx, geom.RectRelF32(bounds.Min.X, bounds.Min.X+size.Y-48, size.X, 24), offset, r)
|
||||
}
|
||||
|
||||
func (r *Research) userTyped(ctx ui.Context, i int) {
|
||||
r.digits[i].Blink()
|
||||
digit := strconv.Itoa(i)
|
||||
if len(r.typing) == 0 || digit != r.typing {
|
||||
r.typing = digit
|
||||
r.digitCount = 1
|
||||
} else {
|
||||
r.digitCount++
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(r.botanist.Number, r.input.Text+r.typing) {
|
||||
r.input.Text = ""
|
||||
r.typing = ""
|
||||
r.digitCount = 0
|
||||
} else if r.digitCount == i || r.digitCount == 10 {
|
||||
r.input.Text += digit
|
||||
r.typing = ""
|
||||
r.digitCount = 0
|
||||
|
||||
if r.input.Text == r.botanist.Number {
|
||||
r.game.UnlockNextFlower(ctx)
|
||||
r.close()
|
||||
r.input.Text = ""
|
||||
}
|
||||
}
|
||||
func (r *Research) CanUserType(digit int) bool {
|
||||
typing := strconv.Itoa(digit)
|
||||
return strings.HasPrefix(r.botanist.Number, r.input.Text+typing)
|
||||
}
|
||||
|
||||
func (r *Research) Handle(ctx ui.Context, event ui.Event) bool {
|
||||
if r.ContainerBase.Handle(ctx, event) {
|
||||
return true
|
||||
}
|
||||
switch e := event.(type) {
|
||||
case *ui.KeyDownEvent:
|
||||
switch e.Key {
|
||||
case ui.Key0:
|
||||
r.userTyped(ctx, 0)
|
||||
case ui.KeyPad0:
|
||||
r.userTyped(ctx, 0)
|
||||
case ui.Key1:
|
||||
r.userTyped(ctx, 1)
|
||||
case ui.KeyPad1:
|
||||
r.userTyped(ctx, 1)
|
||||
case ui.Key2:
|
||||
r.userTyped(ctx, 2)
|
||||
case ui.KeyPad2:
|
||||
r.userTyped(ctx, 2)
|
||||
case ui.Key3:
|
||||
r.userTyped(ctx, 3)
|
||||
case ui.KeyPad3:
|
||||
r.userTyped(ctx, 3)
|
||||
case ui.Key4:
|
||||
r.userTyped(ctx, 4)
|
||||
case ui.KeyPad4:
|
||||
r.userTyped(ctx, 4)
|
||||
case ui.Key5:
|
||||
r.userTyped(ctx, 5)
|
||||
case ui.KeyPad5:
|
||||
r.userTyped(ctx, 5)
|
||||
case ui.Key6:
|
||||
r.userTyped(ctx, 6)
|
||||
case ui.KeyPad6:
|
||||
r.userTyped(ctx, 6)
|
||||
case ui.Key7:
|
||||
r.userTyped(ctx, 7)
|
||||
case ui.KeyPad7:
|
||||
r.userTyped(ctx, 7)
|
||||
case ui.Key8:
|
||||
r.userTyped(ctx, 8)
|
||||
case ui.KeyPad8:
|
||||
r.userTyped(ctx, 8)
|
||||
case ui.Key9:
|
||||
r.userTyped(ctx, 9)
|
||||
case ui.KeyPad9:
|
||||
r.userTyped(ctx, 9)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (r *Research) Hidden() {}
|
||||
|
||||
func (r *Research) Render(ctx ui.Context) {
|
||||
for i := range r.digits {
|
||||
r.digits[i].Tick()
|
||||
}
|
||||
r.ContainerBase.Render(ctx)
|
||||
r.animate.AnimateFn(r.dial.Tick)
|
||||
r.StackPanel.Render(ctx)
|
||||
}
|
||||
|
||||
func (r *Research) onShow(ctx ui.Context) {
|
||||
func (r *Research) Shown() {
|
||||
generateNumber := func() string {
|
||||
var number string
|
||||
for i := 0; i < 3; i++ {
|
||||
@ -201,8 +83,9 @@ func (r *Research) onShow(ctx ui.Context) {
|
||||
}
|
||||
return number
|
||||
}
|
||||
r.digitCount = 0
|
||||
|
||||
r.input.Text = ""
|
||||
r.dial.Reset()
|
||||
|
||||
var specialists string
|
||||
defer func() {
|
||||
@ -226,3 +109,16 @@ func (r *Research) onShow(ctx ui.Context) {
|
||||
specialists += fmt.Sprintf("Botanist: no. %s (unlocks next flower; $ %d)\n", r.botanist.Number, r.botanist.Cost)
|
||||
specialists += "Farmer: no. **unavailable** (fertilizes land; $ ---)\n"
|
||||
}
|
||||
|
||||
func (r *Research) UserGaveWrongInput() {
|
||||
r.input.Text = ""
|
||||
}
|
||||
|
||||
func (r *Research) UserTyped(ctx ui.Context, digit int) {
|
||||
r.input.Text += strconv.Itoa(digit)
|
||||
if r.input.Text == r.botanist.Number {
|
||||
r.game.UnlockNextFlower(ctx)
|
||||
r.input.Text = ""
|
||||
r.closeRequested.Notify(ctx, nil)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user