diff --git a/cmd/tins2020/res/images/game_control_hover.png b/cmd/tins2020/res/images/game_control_hover.png new file mode 100644 index 0000000..f6ee4b2 Binary files /dev/null and b/cmd/tins2020/res/images/game_control_hover.png differ diff --git a/cmd/tins2020/res/images/hover.png b/cmd/tins2020/res/images/tile_hover.png similarity index 100% rename from cmd/tins2020/res/images/hover.png rename to cmd/tins2020/res/images/tile_hover.png diff --git a/cmd/tins2020/res/textures.txt b/cmd/tins2020/res/textures.txt index 70fff51..befdadc 100644 --- a/cmd/tins2020/res/textures.txt +++ b/cmd/tins2020/res/textures.txt @@ -1,8 +1,9 @@ +game-control-hover: images/game_control_hover.png tile-dirt: images/tile_dirt.png tile-grass: images/tile_grass.png tile-snow: images/tile_snow.png -hover: images/hover.png +tile-hover: images/tile_hover.png cactus-small-1: images/cactus_short_NE.png cactus-small-2: images/cactus_short_NW.png diff --git a/cmd/tins2020/tins2020.go b/cmd/tins2020/tins2020.go index ea3fbff..0767cd2 100644 --- a/cmd/tins2020/tins2020.go +++ b/cmd/tins2020/tins2020.go @@ -92,6 +92,8 @@ func run() error { app := tins2020.NewContainer() overlays := tins2020.NewContainer() overlays.AddChild(&tins2020.FPS{}) + gameControls := tins2020.NewGameControls() + overlays.AddChild(gameControls) content := tins2020.NewContainer() app.AddChild(content) app.AddChild(overlays) diff --git a/flower.go b/flower.go index a26325c..9baa89b 100644 --- a/flower.go +++ b/flower.go @@ -34,8 +34,8 @@ type FlowerResistance struct { // NewPoppyTraits creates the traits of a poppy, a very generic flower that thrives in a moderate climate. func NewPoppyTraits() FlowerTraits { return FlowerTraits{ - Spread: 0.01, - Life: 0.9991, + Spread: 0.0007, + Life: 0.99991, Resistance: FlowerResistance{ Cold: 0.3, Hot: 0.3, diff --git a/gamecontrols.go b/gamecontrols.go new file mode 100644 index 0000000..31abc65 --- /dev/null +++ b/gamecontrols.go @@ -0,0 +1,110 @@ +package tins2020 + +import ( + "log" + + "github.com/veandco/go-sdl2/sdl" +) + +type GameControls struct { + ControlBase + + menu ButtonBar + flowers ButtonBar +} + +type ButtonBar struct { + Top int32 + Left int32 + Bottom int32 + Hover int + Buttons []Button +} + +type Button struct { + Icon string + Disabled string + + IsDisabled bool +} + +const buttonBarWidth = 96 + +func (b *ButtonBar) Handle(ctx *Context, event sdl.Event) { + switch e := event.(type) { + case *sdl.MouseMotionEvent: + if e.X > b.Left && e.X < b.Left+buttonBarWidth { + button := int(e.Y-b.Top) / buttonBarWidth + if button < 0 || button >= len(b.Buttons) || b.Buttons[button].IsDisabled { + button = -1 + } + b.Hover = button + } + } +} + +func (b *ButtonBar) Render(ctx *Context) { + ctx.Renderer.FillRect(&sdl.Rect{X: b.Left, Y: b.Top, W: b.Left + buttonBarWidth, H: b.Bottom}) + texture := func(b Button) *Texture { + if b.IsDisabled { + texture := ctx.Textures.Texture(b.Disabled) + if texture != nil { + return texture + } + } + return ctx.Textures.Texture(b.Icon) + } + hoverTexture := ctx.Textures.Texture("game-control-hover") + for i, button := range b.Buttons { + pos := Pt(b.Left, b.Top+int32(i)*buttonBarWidth) + texture := texture(button) + texture.Copy(ctx.Renderer, &sdl.Rect{X: pos.X, Y: pos.Y, W: buttonBarWidth, H: buttonBarWidth}) + if b.Hover == i { + hoverTexture.Copy(ctx.Renderer, hoverTexture.RectOffset(pos)) + } + } +} + +func NewGameControls() *GameControls { + return &GameControls{} +} + +func (c *GameControls) Init(ctx *Context) error { + c.flowers.Buttons = []Button{ + Button{Icon: "flower-poppy-1", Disabled: "flower-red-c-1"}, + Button{Icon: "flower-poppy-1", Disabled: "flower-red-c-1", IsDisabled: true}, + } + return c.updateBarPositions(ctx) +} + +func (c *GameControls) Handle(ctx *Context, event sdl.Event) { + c.menu.Handle(ctx, event) + c.flowers.Handle(ctx, event) + + switch e := event.(type) { + case *sdl.WindowEvent: + switch e.Event { + case sdl.WINDOWEVENT_RESIZED: + err := c.updateBarPositions(ctx) + if err != nil { + log.Fatal(err) + } + } + } +} + +func (c *GameControls) Render(ctx *Context) { + ctx.Renderer.SetDrawColor(74, 198, 154, 255) + c.menu.Render(ctx) + c.flowers.Render(ctx) +} + +func (c *GameControls) updateBarPositions(ctx *Context) error { + w, h, err := ctx.Renderer.GetOutputSize() + if err != nil { + return err + } + c.menu.Top, c.menu.Left, c.menu.Bottom = 0, 0, h + c.flowers.Top, c.flowers.Left, c.flowers.Bottom = 0, w-buttonBarWidth, h + return nil +} diff --git a/math.go b/math.go index 4f221eb..b599c3c 100644 --- a/math.go +++ b/math.go @@ -34,4 +34,6 @@ func Min32(a, b float32) float32 { return b } +func Round32(x float32) float32 { return float32(math.Round(float64(x))) } + func Sqrt32(x float32) float32 { return float32(math.Sqrt(float64(x))) } diff --git a/projection.go b/projection.go index a7cbc81..dd4cb2d 100644 --- a/projection.go +++ b/projection.go @@ -64,7 +64,7 @@ func (p *projection) update(renderer *sdl.Renderer) { log.Fatal(err) } p.windowCenter = Pt(windowW/2, windowH/2) - p.windowRect = sdl.Rect{X: 0, Y: 0, W: windowW - 0, H: windowH - 0} + p.windowRect = sdl.Rect{X: buttonBarWidth, Y: 0, W: windowW - 2*buttonBarWidth, H: windowH - 0} } func (p *projection) visibleTiles(action func(int32, int32, Point)) { diff --git a/terrainrenderer.go b/terrainrenderer.go index 84c0b90..4e7e00d 100644 --- a/terrainrenderer.go +++ b/terrainrenderer.go @@ -4,12 +4,11 @@ import ( "fmt" "github.com/veandco/go-sdl2/sdl" - "opslag.de/schobers/geom" ) type terrainRenderer struct { terrain *Map - hover PointF + hover *Point project projection interact interaction @@ -42,7 +41,12 @@ func (r *terrainRenderer) Handle(ctx *Context, event sdl.Event) { } } case *sdl.MouseMotionEvent: - r.hover = r.project.screenToMap(e.X, e.Y) + if insideRect(e.X, e.Y, &r.project.windowRect) { + hover := r.project.screenToMap(e.X, e.Y) + r.hover = &Point{X: int32(Round32(hover.X)), Y: int32(Round32(hover.Y))} + } else { + r.hover = nil + } if r.interact.mouseDrag != nil { r.project.center = r.project.center.Sub(r.project.screenToMapRel(e.X-r.interact.mouseDrag.X, e.Y-r.interact.mouseDrag.Y)) r.project.update(ctx.Renderer) @@ -63,8 +67,13 @@ func (r *terrainRenderer) Handle(ctx *Context, event sdl.Event) { } } +func insideRect(x, y int32, rect *sdl.Rect) bool { + return x >= rect.X && x < rect.X+rect.W && y >= rect.Y && y < rect.Y+rect.H +} + +func insideRectPt(p Point, rect *sdl.Rect) bool { return insideRect(p.X, p.Y, rect) } + func (r *terrainRenderer) Render(ctx *Context) { - hover := Pt(int32(geom.Round32(r.hover.X)), int32(geom.Round32(r.hover.Y))) toTileTexture := func(x, y int32) *Texture { temp := r.terrain.Temp.Value(x, y) if temp < .35 { @@ -148,8 +157,8 @@ func (r *terrainRenderer) Render(ctx *Context) { rect := r.project.screenToTileRect(pos) text.Copy(ctx.Renderer, rect) - if x == hover.X && y == hover.Y { - ctx.Textures.Texture("hover").Copy(ctx.Renderer, rect) + if r.hover != nil && x == r.hover.X && y == r.hover.Y { + ctx.Textures.Texture("tile-hover").Copy(ctx.Renderer, rect) } })