diff --git a/assets/fonts/NotoSans.ttf b/assets/fonts/NotoSans.ttf new file mode 100755 index 0000000..f7d0d78 Binary files /dev/null and b/assets/fonts/NotoSans.ttf differ diff --git a/pkg/internal/land/object_ui.go b/pkg/internal/land/object_ui.go new file mode 100644 index 0000000..ae121d8 --- /dev/null +++ b/pkg/internal/land/object_ui.go @@ -0,0 +1,21 @@ +package land + +import "github.com/veandco/go-sdl2/sdl" + +type BaseUIObject struct { + BaseObject + + Position Vector2D + Size Vector2D +} + +func (p *BaseUIObject) Draw(pen *sdl.Renderer) { +} + +func (p *BaseUIObject) GetPosition() Vector2D { + return p.Position +} + +func (p *BaseUIObject) GetSize() Vector2D { + return p.Size +} diff --git a/pkg/internal/land/ui/button.go b/pkg/internal/land/ui/button.go new file mode 100644 index 0000000..a301674 --- /dev/null +++ b/pkg/internal/land/ui/button.go @@ -0,0 +1,61 @@ +package ui + +import ( + "git.solsynth.dev/highland/codingland/pkg/internal/land" + "github.com/veandco/go-sdl2/sdl" + "github.com/veandco/go-sdl2/ttf" + "log" +) + +type ButtonObject struct { + land.BaseUIObject + + Label string + Font *ttf.Font + OnClickEvent func(mousePos land.Vector2D) +} + +func (p *ButtonObject) Draw(pen *sdl.Renderer) { + var borderWidth int32 = 2 + + pen.SetDrawColor(255, 255, 255, 255) + pen.FillRect(&sdl.Rect{ + X: int32(p.Position.X), + Y: int32(p.Position.Y), + W: int32(p.Size.X), + H: int32(p.Size.Y), + }) + pen.SetDrawColor(0, 0, 0, 255) + pen.FillRect(&sdl.Rect{ + X: int32(p.Position.X) + borderWidth/2, + Y: int32(p.Position.Y) + borderWidth/2, + W: int32(p.Size.X) - borderWidth, + H: int32(p.Size.Y) - borderWidth, + }) + + surface, err := p.Font.RenderUTF8Blended(p.Label, sdl.Color{R: 255, G: 255, B: 255, A: 255}) + if err != nil { + log.Printf("Failed to render text: %s", err) + return + } + defer surface.Free() + + texture, err := pen.CreateTextureFromSurface(surface) + if err != nil { + log.Printf("Failed to create texture: %s", err) + return + } + defer texture.Destroy() + + textRect := sdl.Rect{ + X: int32(p.BaseUIObject.Position.X), + Y: int32(p.BaseUIObject.Position.Y), + W: surface.W, + H: surface.H, + } + pen.Copy(texture, nil, &textRect) +} + +func (p *ButtonObject) OnClick(mousePos land.Vector2D) { + p.OnClickEvent(mousePos) +} diff --git a/pkg/main.go b/pkg/main.go index 9634110..31a93c4 100644 --- a/pkg/main.go +++ b/pkg/main.go @@ -3,7 +3,9 @@ package main import ( "git.solsynth.dev/highland/codingland/pkg/internal/entities" "git.solsynth.dev/highland/codingland/pkg/internal/land" + "git.solsynth.dev/highland/codingland/pkg/internal/land/ui" "git.solsynth.dev/highland/codingland/pkg/internal/tiles" + "github.com/veandco/go-sdl2/ttf" "log" "runtime" "time" @@ -26,6 +28,11 @@ func main() { } defer sdl.Quit() + if err := ttf.Init(); err != nil { + log.Fatalf("Failed to initialize SDL ttf: %s", err) + } + defer ttf.Quit() + window, err := sdl.CreateWindow("CodingLand", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, windowWidth, windowHeight, sdl.WINDOW_SHOWN) if err != nil { log.Fatalf("Failed to create window: %s", err) @@ -38,7 +45,26 @@ func main() { } defer renderer.Destroy() + sdl.SetHint(sdl.HINT_RENDER_SCALE_QUALITY, "1") + + font, err := ttf.OpenFont("assets/fonts/NotoSans.ttf", 12) + if err != nil { + log.Fatalf("Failed to open font: %s", err) + } + defer font.Close() + root := land.NewRootObject() + root.AddChild(&ui.ButtonObject{ + BaseUIObject: land.BaseUIObject{ + Position: land.Vector2D{X: windowWidth/2 - 60, Y: windowHeight/2 - 25}, + Size: land.Vector2D{X: 120, Y: 50}, + }, + Label: "Hello, World!", + Font: font, + OnClickEvent: func(_ land.Vector2D) { + sdl.ShowSimpleMessageBox(sdl.MESSAGEBOX_INFORMATION, "You clicked me!", "你惊扰了古希腊掌控按钮的神", window) + }, + }) root.AddChild(&entities.Player{ Position: land.Vector2D{X: windowWidth/2 - 25, Y: windowHeight/2 - 25}, Size: land.Vector2D{X: 50, Y: 50},