diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2023-01-24 00:27:50 +0100 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2025-01-27 16:43:44 +0100 |
| commit | 73d40903aecad3efcf7c6055c133f0db86558203 (patch) | |
| tree | e9c8f00fb186e270da92f273f570579f2d0b0d95 /go/ui | |
| parent | fbba48698d8f8b83dfd7d914b0e37338e0d4e2ef (diff) | |
| download | muhqs-game-73d40903aecad3efcf7c6055c133f0db86558203.tar.gz muhqs-game-73d40903aecad3efcf7c6055c133f0db86558203.zip | |
intermediate commit
Diffstat (limited to 'go/ui')
| -rw-r--r-- | go/ui/buffer.go | 39 | ||||
| -rw-r--r-- | go/ui/button.go | 45 | ||||
| -rw-r--r-- | go/ui/choice.go | 8 | ||||
| -rw-r--r-- | go/ui/font.go | 24 | ||||
| -rw-r--r-- | go/ui/hand.go | 68 | ||||
| -rw-r--r-- | go/ui/mapView.go | 19 | ||||
| -rw-r--r-- | go/ui/stateBar.go | 42 | ||||
| -rw-r--r-- | go/ui/textBox.go | 42 | ||||
| -rw-r--r-- | go/ui/widget.go | 40 |
9 files changed, 219 insertions, 108 deletions
diff --git a/go/ui/buffer.go b/go/ui/buffer.go index cc9f2377..e0e6b001 100644 --- a/go/ui/buffer.go +++ b/go/ui/buffer.go @@ -5,6 +5,8 @@ import ( "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/text" + + "muhq.space/muhqs-game/go/font" ) var ( @@ -13,47 +15,30 @@ var ( ) type Buffer struct { - X, Y int - Width, Height int - img *ebiten.Image - lines []string - pos int + WidgetBase + lines []string + pos int } func NewBuffer(x, y int, width, height int) *Buffer { - return &Buffer{x, y, width, height, nil, []string{}, 0} + b := &Buffer{NewWidgetBase(x, y, width, height), []string{}, 0} + b.renderImpl = func() *ebiten.Image { return b.render() } + return b } -func (b *Buffer) render() { +func (b *Buffer) render() *ebiten.Image { img := ebiten.NewImage(b.Width, b.Height) img.Fill(BUFFER_BACKGROUND) y := 0 for _, line := range b.lines[b.pos:] { - bounds := text.BoundString(Font, line) + bounds := text.BoundString(font.Font, line) y += bounds.Dy() if y > b.Height { break } - text.Draw(img, line, Font, 0, y, BUFFER_FOREGROUND) - } - b.img = img -} - -func (b *Buffer) Draw(screen *ebiten.Image) { - if b.img == nil { - b.render() + text.Draw(img, line, font.Font, 0, y, BUFFER_FOREGROUND) } - op := &ebiten.DrawImageOptions{} - op.GeoM.Translate(float64(b.X), float64(b.Y)) - screen.DrawImage(b.img, op) -} - -func (b *Buffer) FindObjectAt(x, y int) interface{} { - return nil -} - -func (b *Buffer) ForceRedraw() { - b.img = nil + return img } func (b *Buffer) AddLines(lines []string) { diff --git a/go/ui/button.go b/go/ui/button.go index 93180204..97dbad22 100644 --- a/go/ui/button.go +++ b/go/ui/button.go @@ -6,43 +6,36 @@ import ( "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/ebitenutil" "github.com/hajimehoshi/ebiten/v2/text" + + "muhq.space/muhqs-game/go/font" ) type Button interface { Widget - Contains(x, y int) bool Click(x, y int) } type SimpleButton struct { - X, Y int - Width, Height int - img *ebiten.Image - OnClick func(b *SimpleButton) + WidgetBase + label string + OnClick func(b *SimpleButton) + BG color.Color + FG color.Color } -func NewSimpleButton(x, y, w, h int, onClick func(b *SimpleButton), label string) *SimpleButton { - img := ebiten.NewImage(w, h) - - // b := text.BoundString(f, label) - ebitenutil.DrawRect(img, float64(0), float64(0), float64(w), float64(h), gray) - text.Draw(img, label, Font, 20, 25, color.White) - - return &SimpleButton{x, y, w, h, img, onClick} +func NewSimpleButton(x, y, w, h int, label string, onClick func(b *SimpleButton)) *SimpleButton { + sb := &SimpleButton{NewWidgetBase(x, y, w, h), label, onClick, gray, color.White} + sb.renderImpl = func() *ebiten.Image { return sb.render() } + return sb } -func (b *SimpleButton) Draw(screen *ebiten.Image) { - op := &ebiten.DrawImageOptions{} - op.GeoM.Translate(float64(b.X), float64(b.Y)) - screen.DrawImage(b.img, op) -} - -func (b *SimpleButton) Click(x, y int) { - b.OnClick(b) -} +func (b *SimpleButton) render() *ebiten.Image { + img := ebiten.NewImage(b.Width, b.Height) -func (b *SimpleButton) Contains(x, y int) bool { - return x >= b.X && x <= b.X+b.Width && y >= b.Y && y <= b.Y+b.Height + // b := text.BoundString(f, label) + ebitenutil.DrawRect(img, float64(0), float64(0), float64(b.Width), float64(b.Height), b.BG) + text.Draw(img, b.label, font.Font, 20, 25, b.FG) + return img } func (b *SimpleButton) FindObjectAt(x, y int) interface{} { @@ -51,3 +44,7 @@ func (b *SimpleButton) FindObjectAt(x, y int) interface{} { } return nil } + +func (b *SimpleButton) Click(x, y int) { + b.OnClick(b) +} diff --git a/go/ui/choice.go b/go/ui/choice.go index 2020ed0a..71308d1b 100644 --- a/go/ui/choice.go +++ b/go/ui/choice.go @@ -21,8 +21,8 @@ func NewChoice(x, y int, width, choiceHeight int, choices []string, c := &Choice{x, y, width, choiceHeight, choices, onClick, []Button{}} for i, choice := range c.choices { - b := NewSimpleButton(c.X, c.Y+i*c.choiceHeight, c.Width, c.choiceHeight, - choiceButtonOnClickDummy, choice) + b := NewSimpleButton(c.X, c.Y+i*c.choiceHeight, c.Width, c.choiceHeight, choice, + choiceButtonOnClickDummy) c.buttons = append(c.buttons, b) } @@ -55,6 +55,10 @@ func (c *Choice) FindObjectAt(x, y int) interface{} { return nil } +func (c *Choice) Render() *ebiten.Image { + return nil +} + func NewActionChoice(x, y int, actions []game.ActionPrototype, onClick func(*Choice, int, int)) *Choice { // TODO: use dynamic with width and height width := 200 diff --git a/go/ui/font.go b/go/ui/font.go deleted file mode 100644 index 065ac0d8..00000000 --- a/go/ui/font.go +++ /dev/null @@ -1,24 +0,0 @@ -package ui - -import ( - "log" - - "golang.org/x/image/font" - "golang.org/x/image/font/gofont/goregular" - "golang.org/x/image/font/opentype" -) - -var Font font.Face - -func InitFont() { - tt, err := opentype.Parse(goregular.TTF) - if err != nil { - log.Fatal(err) - } - - opts := &opentype.FaceOptions{Size: 24, DPI: 72} - Font, err = opentype.NewFace(tt, opts) - if err != nil { - log.Fatal(err) - } -} diff --git a/go/ui/hand.go b/go/ui/hand.go new file mode 100644 index 00000000..0fdde253 --- /dev/null +++ b/go/ui/hand.go @@ -0,0 +1,68 @@ +package ui + +import ( + "log" + + "github.com/hajimehoshi/ebiten/v2" + "muhq.space/muhqs-game/go/assets" + "muhq.space/muhqs-game/go/game" +) + +const ( + HAND_CARD_WIDTH = 200 +) + +type HandCard struct { + C *game.Card +} + +type HandView struct { + WidgetBase + hand *game.Hand + scale float64 +} + +func NewHandView(x, y, width, height int, h *game.Hand) *HandView { + hv := &HandView{NewWidgetBase(x, y, width, height), h, -1} + hv.renderImpl = func() *ebiten.Image { return hv.render() } + return hv +} + +func (hv *HandView) render() *ebiten.Image { + img := ebiten.NewImage(hv.Width, hv.Height) + for i, card := range hv.hand.GetCards() { + cardImg := assets.GetCard(card.Path(), "en") + if cardImg == nil { + log.Fatalf("No image found for %s", card.Path()) + } + + if hv.scale == -1 { + b := cardImg.Bounds() + x_scale := float64(HAND_CARD_WIDTH) / float64(b.Dx()) + y_scale := float64(hv.Height) / float64(b.Dy()) + hv.scale = x_scale + if y_scale < x_scale { + hv.scale = y_scale + } + } + + op := &ebiten.DrawImageOptions{} + op.GeoM.Scale(hv.scale, hv.scale) + op.GeoM.Translate(float64(i*HAND_CARD_WIDTH), 0) + img.DrawImage(cardImg, op) + } + return img +} + +func (hv *HandView) FindObjectAt(x, y int) interface{} { + if !hv.Contains(x, y) { + return nil + } + + i := x / HAND_CARD_WIDTH + if i >= hv.hand.Size() { + return nil + } + + return HandCard{hv.hand.GetCards()[i]} +} diff --git a/go/ui/mapView.go b/go/ui/mapView.go index 39c92ae4..6c887920 100644 --- a/go/ui/mapView.go +++ b/go/ui/mapView.go @@ -1,9 +1,11 @@ package ui import ( + "fmt" "log" "math" "strings" + "unicode" "golang.org/x/exp/slices" @@ -33,6 +35,10 @@ func NewMapView(g *game.State) *MapView { return &vw } +func (mv *MapView) GetHeight() int { + return len(mv.gameState.Map.Tiles) * TILE_HEIGHT +} + func rotateStreetImg(x, y int, radian float64, op *ebiten.DrawImageOptions) { // Move the image's center to the screen's upper-left corner. // This is a preparation for rotating. When geometry matrices are applied, @@ -130,11 +136,14 @@ func (vw *MapView) drawPermanentsLayer(screen *ebiten.Image) { if vw.permanentsLayer == nil { vw.permanentsLayer = vw.newLayerImage() - for _, p := range vw.gameState.Permanents { + for i, p := range vw.gameState.Permanents { permanentSymbol := assets.GetSymbol(strings.ToLower(p.GetCard().Name)) - // TODO: Implement generic symbols if permanentSymbol == nil { - continue + symbol := fmt.Sprintf("%c%d", unicode.ToUpper(rune(p.GetCard().Type.String()[0])), i) + permanentSymbol = assets.GetGenericSymbol(symbol) + if permanentSymbol == nil { + log.Fatalf("Failed to generate generic symbol %s", symbol) + } } t := p.GetTile() @@ -225,3 +234,7 @@ func (vw *MapView) HighlightPermanent(p game.Permanent) { func (vw *MapView) ClearPermanentsHighlights() { vw.HighlightPermanents([]game.Permanent{}) } + +func (*MapView) Render(Widget) *ebiten.Image { + return nil +} diff --git a/go/ui/stateBar.go b/go/ui/stateBar.go new file mode 100644 index 00000000..e175c0c5 --- /dev/null +++ b/go/ui/stateBar.go @@ -0,0 +1,42 @@ +package ui + +import ( + "fmt" + + "github.com/hajimehoshi/ebiten/v2" + "muhq.space/muhqs-game/go/game" +) + +type StateBar struct { + X, Y int + Width, Height int + gameState *game.State + activePlayer *game.Player + ressourceView *TextBox +} + +func NewStateBar(x, y int, width, height int, s *game.State, p *game.Player) *StateBar { + sb := &StateBar{x, y, width, height, s, p, nil} + return sb +} + +func (sb *StateBar) ressourceLabel() string { + return fmt.Sprintf("%d", sb.activePlayer.Ressource) +} + +func (sb *StateBar) Draw(screen *ebiten.Image) { + if sb.ressourceView == nil { + sb.ressourceView = NewFixedTextBox(sb.X, sb.Y+sb.Height-sb.Width, sb.Width, sb.Width, + sb.ressourceLabel()) + } + sb.ressourceView.Draw(screen) +} + +func (sb *StateBar) FindObjectAt(x, y int) interface{} { + return nil +} + +func (sb *StateBar) ForceRedraw() { + sb.ressourceView.Text = sb.ressourceLabel() + sb.ressourceView = nil +} diff --git a/go/ui/textBox.go b/go/ui/textBox.go index e07440b5..5e2d140b 100644 --- a/go/ui/textBox.go +++ b/go/ui/textBox.go @@ -6,31 +6,30 @@ import ( "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/text" + "muhq.space/muhqs-game/go/font" "muhq.space/muhqs-game/go/game" ) var ( TEXTBOX_BACKGROUND = gray TEXTBOX_FOREGROUND = color.White + + TEXTBOX_AUTO_BORDER = 3 ) type TextBox struct { - X, Y int - Width, Height int - img *ebiten.Image - text string + WidgetBase + Text string } func NewFixedTextBox(x, y int, width, height int, t string) *TextBox { - tb := &TextBox{x, y, width, height, nil, t} - tb.render() + tb := &TextBox{NewWidgetBase(x, y, width, height), t} + tb.renderImpl = func() *ebiten.Image { return tb.render() } return tb } func NewAutoTextBox(x, y int, t string) *TextBox { - tb := &TextBox{x, y, -1, -1, nil, t} - tb.render() - return tb + return NewFixedTextBox(x, y, -1, -1, t) } func NewUnitInfo(x, y int, u *game.Unit) *TextBox { @@ -45,23 +44,14 @@ func NewPermInfo(x, y int, p game.Permanent) *TextBox { return NewAutoTextBox(x, y, info) } -func (tb *TextBox) render() { - b := text.BoundString(Font, tb.text) +func (tb *TextBox) render() *ebiten.Image { + b := text.BoundString(font.Font, tb.Text) if tb.Width == -1 || tb.Height == -1 { - tb.Width = b.Dx() - tb.Height = b.Dy() + tb.Width = b.Dx() + 2*TEXTBOX_AUTO_BORDER + tb.Height = b.Dy() + 2*TEXTBOX_AUTO_BORDER } - tb.img = ebiten.NewImage(tb.Width, tb.Height) - tb.img.Fill(TEXTBOX_BACKGROUND) - text.Draw(tb.img, tb.text, Font, b.Min.X, -b.Min.Y, TEXTBOX_FOREGROUND) -} - -func (tb *TextBox) Draw(screen *ebiten.Image) { - op := &ebiten.DrawImageOptions{} - op.GeoM.Translate(float64(tb.X), float64(tb.Y)) - screen.DrawImage(tb.img, op) -} - -func (tb TextBox) FindObjectAt(x, y int) interface{} { - return nil + img := ebiten.NewImage(tb.Width, tb.Height) + img.Fill(TEXTBOX_BACKGROUND) + text.Draw(img, tb.Text, font.Font, TEXTBOX_AUTO_BORDER+b.Min.X, TEXTBOX_AUTO_BORDER-b.Min.Y, TEXTBOX_FOREGROUND) + return img } diff --git a/go/ui/widget.go b/go/ui/widget.go index c8fb0816..d783eb36 100644 --- a/go/ui/widget.go +++ b/go/ui/widget.go @@ -5,6 +5,42 @@ import ( ) type Widget interface { - Draw(screen *ebiten.Image) - FindObjectAt(x, y int) interface{} + Draw(*ebiten.Image) + FindObjectAt(int, int) interface{} +} + +type WidgetBase struct { + X, Y int + Width, Height int + img *ebiten.Image + renderImpl func() *ebiten.Image +} + +func renderDummy() *ebiten.Image { + return nil +} + +func NewWidgetBase(x, y, width, height int) WidgetBase { + return WidgetBase{x, y, width, height, nil, renderDummy} +} + +func (w *WidgetBase) Draw(screen *ebiten.Image) { + if w.img == nil { + w.img = w.renderImpl() + } + op := &ebiten.DrawImageOptions{} + op.GeoM.Translate(float64(w.X), float64(w.Y)) + screen.DrawImage(w.img, op) +} + +func (w *WidgetBase) ForceRedraw() { + w.img = nil +} + +func (w *WidgetBase) Contains(x, y int) bool { + return x >= 0 && y >= 0 && x >= w.X && x <= w.X+w.Width && y >= w.Y && y <= w.Y+w.Height +} + +func (w *WidgetBase) FindObjectAt(int, int) interface{} { + return nil } |
