From 573396054f098560719f20838937f3b9951e3980 Mon Sep 17 00:00:00 2001 From: Ben Vezzani Date: Wed, 27 Aug 2025 23:22:39 -0400 Subject: [PATCH] okay new ux idea --- common/elements/v1/block.go | 65 ++++++++--------------------- common/elements/v1/button.go | 20 ++++----- common/elements/v1/element.go | 48 ++++++---------------- common/elements/v1/stack.go | 31 ++++++++++++++ common/elements/v1/table.go | 20 +++------ common/sprites/v1/sprite.go | 62 +++++++++++++++++----------- tools/spritedit/editor.go | 21 ++++++++++ tools/spritedit/main.go | 77 +---------------------------------- 8 files changed, 134 insertions(+), 210 deletions(-) create mode 100644 common/elements/v1/stack.go create mode 100644 tools/spritedit/editor.go diff --git a/common/elements/v1/block.go b/common/elements/v1/block.go index 4c71109..64d9a14 100644 --- a/common/elements/v1/block.go +++ b/common/elements/v1/block.go @@ -1,61 +1,28 @@ package elements import ( - "context" - "image/color" - - "git.vezzani.net/ben/games/common/ux/v1" "github.com/hajimehoshi/ebiten/v2" - "github.com/hajimehoshi/ebiten/v2/vector" - "golang.org/x/image/font" ) -type Block struct { - Label string - Style struct { - Width float32 - Height float32 - XAlign XAlign - YAlign YAlign - Offset int - Font *font.Face - BackgroundColor *color.Color - } -} +type BlockOption func(*block) -func (b *Block) backgroundColor() color.Color { - var c *color.Color - if b.Style.BackgroundColor != nil { - c = b.Style.BackgroundColor - } else { - c = &ux.BackgroundColor - } - - return *c -} - -func (b *Block) size(ctx context.Context) (x, y float32) { - x = b.Style.Width - y = b.Style.Height - - if x == 0 || y == 0 { - px, py := GetContainerSize(ctx) - if x == 0 { - x = px - } - if y == 0 { - y = py +func Block(ops ...BlockOption) ElementFunc { + return func(d Dimensions) Element { + b := block{} + for i := range ops { + ops[i](&b) } + return &b } - - return } -func (b *Block) Draw(ctx context.Context, image *ebiten.Image) error { - xz, yz := GetZero(ctx) - w, h := b.size(ctx) - - vector.StrokeRect(image, xz, yz, w, h, 1, b.backgroundColor(), true) - - return nil +type block struct { + width float64 + height float64 + xAlign xAlign + yAlign yAlign +} + +func (b block) Draw(image *ebiten.Image, anchorX, anchorY float64) (w, h float64) { + return b.width, b.height } diff --git a/common/elements/v1/button.go b/common/elements/v1/button.go index 8d21ce3..8a34c96 100644 --- a/common/elements/v1/button.go +++ b/common/elements/v1/button.go @@ -10,24 +10,24 @@ import ( ) import "git.vezzani.net/ben/games/common/ux/v1" -type XAlign int -type YAlign int +type xAlign int +type yAlign int const ( - AlignCente XAlign = iota + AlignCente xAlign = iota AlignLeft AlignRight ) const ( - AlignCenter YAlign = iota + AlignCenter yAlign = iota AlignTop AlignBottom ) type Button struct { mouseHandler - Block + block Label string OnClick func() error OnRightClick func() error @@ -44,17 +44,17 @@ func (b *Button) HandleClick(_ MouseState) error { } func (b *Button) getFont() font.Face { - if b.Block.Style.Font == nil { + if b.block.block.Font == nil { return ux.FontFace } - return *b.Block.Style.Font + return *b.block.block.Font } func (b *Button) backgroundColor() color.Color { var c *color.Color - if b.Block.Style.BackgroundColor != nil { - c = b.Block.Style.BackgroundColor + if b.block.block.BackgroundColor != nil { + c = b.block.block.BackgroundColor } else { c = &ux.BackgroundColor } @@ -67,8 +67,6 @@ func (b *Button) backgroundColor() color.Color { } func (b *Button) Draw(ctx context.Context, image *ebiten.Image) error { - xz, yz := GetZero(ctx) - w, h := b.size(ctx) vector.StrokeRect(image, xz, yz, w, h, 1, b.backgroundColor(), true) diff --git a/common/elements/v1/element.go b/common/elements/v1/element.go index 411c511..8e28b6f 100644 --- a/common/elements/v1/element.go +++ b/common/elements/v1/element.go @@ -1,60 +1,36 @@ package elements import ( - "context" - "github.com/hajimehoshi/ebiten/v2" ) +type ElementFunc func(Dimensions) Element + type MouseState struct { X, Y int32 LeftDown, RightDown bool LeftChanged, RightChanged bool } -const ( - ContainerSizeKey = "container_size" - ZeroKey = "zero" -) - type Clickable interface { - Element - HandleClick(ctx context.Context, s MouseState) error + HandleClick(s MouseState) error } type Mouseable interface { - Element - HandleMouseEnter(ctx context.Context, s MouseState) error - HandleMouseLeave(ctx context.Context, s MouseState) error - HandleMouseMove(ctx context.Context, s MouseState) error - HandleMouseDown(ctx context.Context, s MouseState) error - HandleMouseUp(ctx context.Context, s MouseState) error + HandleMouseEnter(s MouseState) error + HandleMouseLeave(s MouseState) error + HandleMouseMove(s MouseState) error + HandleMouseDown(s MouseState) error + HandleMouseUp(s MouseState) error } type Element interface { - Draw(ctx context.Context, image *ebiten.Image) error + Draw(image *ebiten.Image, anchorX, anchorY float64) (w, h float64) } -func SetZero(ctx context.Context, x, y float32) context.Context { - return context.WithValue(ctx, ZeroKey, [2]float32{x, y}) -} - -func SetContainerSize(ctx context.Context, w, h float32) context.Context { - return context.WithValue(ctx, ContainerSizeKey, [2]float32{w, h}) -} - -func GetZero(ctx context.Context) (x, y float32) { - if v, ok := ctx.Value(ZeroKey).([2]float32); ok { - return v[0], v[1] - } - return 0, 0 -} - -func GetContainerSize(ctx context.Context) (w, h float32) { - if s, ok := ctx.Value(ContainerSizeKey).([2]float32); ok { - return s[0], s[1] - } - return 0, 0 +type Dimensions struct { + zx, zy float64 + wx, wy float64 } type mouseHandler struct { diff --git a/common/elements/v1/stack.go b/common/elements/v1/stack.go new file mode 100644 index 0000000..c7450eb --- /dev/null +++ b/common/elements/v1/stack.go @@ -0,0 +1,31 @@ +package elements + +import "github.com/hajimehoshi/ebiten/v2" + +type StackOption func(*stack) + +func Stack(ops ...StackOption) ElementFunc { + return func(parentDimensions Dimensions) Element { + + } +} + +type stack struct { + block + horizontal bool + children []Element +} + +func (s *stack) Draw(image *ebiten.Image, anchorX, anchorY float64) (w, h float64) { + var offsetX, offsetY float64 + originalX, originalY := anchorX, anchorY + for i := range s.children { + offsetX, offsetY = s.children[i].Draw(image, anchorX, anchorY) + if s.horizontal { + anchorX += offsetX + } else { + anchorY += offsetY + } + } + return anchorX - originalX, anchorY - originalY +} diff --git a/common/elements/v1/table.go b/common/elements/v1/table.go index 34af0f5..e546916 100644 --- a/common/elements/v1/table.go +++ b/common/elements/v1/table.go @@ -9,12 +9,12 @@ import ( type Table struct { mouseHandler - Block + block ColumnCount int RowCount int - Cells []Element + Cells []Dimensions Style struct { } @@ -70,8 +70,8 @@ func (t *Table) HandleMouseUp(ctx context.Context, s MouseState) error { return nil } -func (t *Table) CellSize(ctx context.Context) (w, h float32) { - w, h = GetContainerSize(ctx) +func (t *Table) CellSize() (w, h float32) { + w, h = t. return w / float32(t.ColumnCount), h / float32(t.RowCount) } @@ -83,16 +83,8 @@ func (t *Table) CellZero(ctx context.Context, addr int) (x, y float32) { return x + float32(col)*w, y + float32(row) + h } -func (t *Table) Draw(ctx context.Context, screen *ebiten.Image) error { - -} - -func (t *Table) contextForCell(ctx context.Context, addr int) context.Context { - zx, zy := t.CellZero(ctx, addr) - w, h := t.CellSize(ctx) - ctx = SetZero(ctx, zx, zy) - ctx = SetContainerSize(ctx, w, h) - return ctx +func (t *Table) Draw(screen *ebiten.Image, zx, zy float64) error { + return nil } func (t *Table) getAddressUnderMouse() int { diff --git a/common/sprites/v1/sprite.go b/common/sprites/v1/sprite.go index fda3b21..9d32149 100644 --- a/common/sprites/v1/sprite.go +++ b/common/sprites/v1/sprite.go @@ -3,7 +3,7 @@ package sprites import ( "image" - "git.vezzani.net/ben/games/common/window/v1" + "git.vezzani.net/ben/games/common/ux/v1" "github.com/hajimehoshi/ebiten/v2" ) @@ -16,9 +16,9 @@ func Update() { } type animation struct { - RowNumber uint8 - FrameCount uint8 - Scale float32 + RowNumber uint8 + TickCount uint8 + Scale float32 } type subImager interface { @@ -31,7 +31,12 @@ type Sprite struct { imgData subImager animations map[string]animation - baseAnim *animation + baseAnim *animation + currentAnim *animation + + animationStartedAt int + animationStopAt int + animateOnce bool } func (s *Sprite) baseAnimation() animation { @@ -50,22 +55,17 @@ func (s *Sprite) baseAnimation() animation { return animation{} } -func (s *Sprite) getAnimation(id string) animation { - if id == "" { - return s.baseAnimation() +func (s *Sprite) getAnimation() animation { + if s.currentAnim != nil { + return *s.currentAnim } - - if anim, ok := s.animations[id]; ok { - return anim - } - return s.baseAnimation() } func (s *Sprite) Image(ops imageOptions) image.Image { - anim := s.getAnimation(ops.animation) + anim := s.getAnimation() - xOffset := updateCount % int(anim.FrameCount) * s.width + xOffset := updateCount % int(anim.TickCount) * s.width yOffset := int(anim.RowNumber) * s.height r := image.Rect(xOffset, yOffset, s.width, s.height).Intersect(s.imgData.Bounds()) @@ -74,9 +74,12 @@ func (s *Sprite) Image(ops imageOptions) image.Image { } func (s *Sprite) Draw(screen *ebiten.Image, options ...ImageOption) { + if s.getAnimation().RowNumber == 0 { + } + ops := imageOptions{ - scaleX: window.Scale, - scaleY: window.Scale, + scaleX: ux.Scale, + scaleY: ux.Scale, } for _, o := range options { @@ -98,11 +101,28 @@ func (s *Sprite) Draw(screen *ebiten.Image, options ...ImageOption) { ) } +func (s *Sprite) StartAnimation(id string, once bool) { + if a, ok := s.animations[id]; ok { + s.currentAnim = &a + } + if once { + s.animateOnce = true + s.animationStopAt = updateCount + int(s.currentAnim.TickCount) + } + s.animationStartedAt = updateCount +} + +func (s *Sprite) StopAnimation() { + s.currentAnim = nil + s.animationStartedAt = 0 + s.animationStopAt = 0 + s.animateOnce = false +} + type imageOptions struct { x, y float64 scaleX, scaleY float64 rotateTheta float64 - animation string } type ImageOption func(options *imageOptions) @@ -114,12 +134,6 @@ func ToScale(x, y float64) ImageOption { } } -func Animation(name string) ImageOption { - return func(o *imageOptions) { - o.animation = name - } -} - func AtPosition(x, y float64) ImageOption { return func(o *imageOptions) { o.x, o.y = x, y diff --git a/tools/spritedit/editor.go b/tools/spritedit/editor.go new file mode 100644 index 0000000..7f88726 --- /dev/null +++ b/tools/spritedit/editor.go @@ -0,0 +1,21 @@ +package main + +import "github.com/hajimehoshi/ebiten/v2" + +type editor struct { +} + +func (e *editor) Update() error { + //TODO implement me + panic("implement me") +} + +func (e *editor) Draw(screen *ebiten.Image) { + //TODO implement me + panic("implement me") +} + +func (e *editor) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) { + //TODO implement me + panic("implement me") +} diff --git a/tools/spritedit/main.go b/tools/spritedit/main.go index 4457d0b..16c432c 100644 --- a/tools/spritedit/main.go +++ b/tools/spritedit/main.go @@ -3,88 +3,13 @@ package main import ( "bytes" - "github.com/ebitenui/ebitenui" - "github.com/ebitenui/ebitenui/image" - "github.com/ebitenui/ebitenui/widget" "github.com/hajimehoshi/ebiten/v2" - "github.com/hajimehoshi/ebiten/v2/text/v2" - "golang.org/x/image/colornames" - "golang.org/x/image/font/gofont/goregular" ) -type Editor struct { - ui *ebitenui.UI -} - -func NewEditor() *Editor { - root := widget.NewContainer( - widget.ContainerOpts.BackgroundImage( - image.NewNineSliceColor(colornames.Gainsboro), - )) - root.AddChild( - widget.NewButton( - widget.ButtonOpts.TextLabel("Open Sprite Sheet..."), - widget.ButtonOpts.TextFace(DefaultFont()), - widget.ButtonOpts.TextColor(&widget.ButtonTextColor{ - Idle: colornames.Gainsboro, - Hover: colornames.Gainsboro, - Pressed: colornames.Gainsboro, - }), - widget.ButtonOpts.Image(&widget.ButtonImage{ - Idle: DefaultNineSlice(colornames.Darkslategray), - Hover: DefaultNineSlice(Mix(colornames.Darkslategray, colornames.Mediumseagreen, 0.4)), - Disabled: DefaultNineSlice(Mix(colornames.Darkslategray, colornames.Gainsboro, 0.8)), - Pressed: PressedNineSlice(Mix(colornames.Darkslategray, colornames.Black, 0.4)), - PressedHover: PressedNineSlice(Mix(colornames.Darkslategray, colornames.Black, 0.4)), - }), - widget.ButtonOpts.WidgetOpts( - widget.WidgetOpts.LayoutData(widget.AnchorLayoutData{ - VerticalPosition: widget.AnchorLayoutPositionCenter, - HorizontalPosition: widget.AnchorLayoutPositionCenter, - }), - widget.WidgetOpts.MinSize(180, 48), - ), - ), - ) - - return &Editor{ - ui: &ebitenui.UI{Container: root}, - } -} - -func (e *Editor) Update() error { - e.ui.Update() - return nil -} - -func (e *Editor) Draw(screen *ebiten.Image) { - e.ui.Draw(screen) -} - -func (e *Editor) Layout(w, h int) (int, int) { - return w, h -} - -func DefaultFont() *text.Face { - s, err := text.NewGoTextFaceSource(bytes.NewReader(goregular.TTF)) - if err != nil { - panic(err) - } - - var f text.Face - - f = &text.GoTextFace{ - Source: s, - Size: 20, - } - - return &f -} - func main() { ebiten.SetWindowSize(480, 320) ebiten.SetWindowResizingMode(ebiten.WindowResizingModeEnabled) - if err := ebiten.RunGame(NewEditor()); err != nil { + if err := ebiten.RunGame(); err != nil { panic(err) } }