Sander Schobers
9641719579
Refactored event handling to be able to "handle" events so no other controls will handle the same event again.
206 lines
5.2 KiB
Go
206 lines
5.2 KiB
Go
package tins2020
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/veandco/go-sdl2/sdl"
|
|
)
|
|
|
|
type terrainRenderer struct {
|
|
game *Game
|
|
hover *Point
|
|
project projection
|
|
|
|
drag Drageable
|
|
}
|
|
|
|
func NewTerrainRenderer(game *Game) Control {
|
|
return &terrainRenderer{game: game, project: newProjection()}
|
|
}
|
|
|
|
func (r *terrainRenderer) Arrange(ctx *Context, _ Rectangle) {
|
|
r.project.update(ctx.Renderer)
|
|
}
|
|
|
|
func (r *terrainRenderer) Init(ctx *Context) error {
|
|
r.game.CenterChanged().RegisterItf(func(state interface{}) {
|
|
center := state.(Point)
|
|
r.project.center = center.ToPtF()
|
|
r.project.update(ctx.Renderer)
|
|
})
|
|
r.project.update(ctx.Renderer)
|
|
return nil
|
|
}
|
|
|
|
func isControlKeyDown() bool {
|
|
state := sdl.GetKeyboardState()
|
|
return state[sdl.SCANCODE_LCTRL] == 1 || state[sdl.SCANCODE_RCTRL] == 1
|
|
}
|
|
|
|
func (r *terrainRenderer) Handle(ctx *Context, event sdl.Event) bool {
|
|
switch e := event.(type) {
|
|
case *sdl.MouseButtonEvent:
|
|
if r.project.windowInteractRect.IsPointInside(e.X, e.Y) {
|
|
if e.Type == sdl.MOUSEBUTTONDOWN {
|
|
if e.Button == sdl.BUTTON_MIDDLE || (e.Button == sdl.BUTTON_LEFT && isControlKeyDown()) {
|
|
if !r.drag.IsDragging() {
|
|
r.drag.Start(Pt(e.X, e.Y))
|
|
}
|
|
}
|
|
if e.Button == sdl.BUTTON_LEFT {
|
|
pos := r.project.screenToMapInt(e.X, e.Y)
|
|
r.game.UserClickedTile(pos)
|
|
}
|
|
if e.Button == sdl.BUTTON_RIGHT {
|
|
if e.Type == sdl.MOUSEBUTTONDOWN {
|
|
r.game.CancelTool()
|
|
}
|
|
}
|
|
}
|
|
if e.Type == sdl.MOUSEBUTTONUP {
|
|
if r.drag.IsDragging() {
|
|
r.game.Terrain.Center = mapToTile(r.project.center)
|
|
r.drag.Cancel()
|
|
}
|
|
}
|
|
}
|
|
case *sdl.MouseMotionEvent:
|
|
if r.project.windowInteractRect.IsPointInside(e.X, e.Y) {
|
|
hover := r.project.screenToMapInt(e.X, e.Y)
|
|
r.hover = &hover
|
|
} else {
|
|
r.hover = nil
|
|
}
|
|
if r.drag.IsDragging() {
|
|
delta := r.drag.Move(Pt(e.X, e.Y))
|
|
r.project.center = r.project.center.Sub(r.project.screenToMapRel(delta.X, delta.Y))
|
|
r.project.update(ctx.Renderer)
|
|
}
|
|
case *sdl.MouseWheelEvent:
|
|
if r.hover != nil {
|
|
zoom := r.project.zoom
|
|
if e.Y < 0 && r.project.zoom > .25 {
|
|
zoom *= .5
|
|
} else if e.Y > 0 && r.project.zoom < 2 {
|
|
zoom *= 2
|
|
}
|
|
if zoom != r.project.zoom {
|
|
hover := r.hover.ToPtF()
|
|
r.project.center = hover.Sub(hover.Sub(r.project.center).Mul(r.project.zoom / zoom))
|
|
r.project.zoom = zoom
|
|
r.project.update(ctx.Renderer)
|
|
}
|
|
}
|
|
case *sdl.WindowEvent:
|
|
if e.Event == sdl.WINDOWEVENT_LEAVE {
|
|
r.hover = nil
|
|
r.project.update(ctx.Renderer)
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (r *terrainRenderer) Render(ctx *Context) {
|
|
terrain := r.game.Terrain
|
|
toTileTexture := func(x, y int32) *Texture {
|
|
temp := terrain.Temp.Value(x, y)
|
|
if temp < .35 {
|
|
return ctx.Textures.Texture("tile-snow")
|
|
}
|
|
if temp > .65 {
|
|
return ctx.Textures.Texture("tile-dirt")
|
|
}
|
|
return ctx.Textures.Texture("tile-grass")
|
|
}
|
|
|
|
variantToInt := func(variant float64) int {
|
|
if variant < .25 {
|
|
return 1
|
|
}
|
|
if variant < .5 {
|
|
return 2
|
|
}
|
|
if variant < .75 {
|
|
return 3
|
|
}
|
|
if variant < 1 {
|
|
return 4
|
|
}
|
|
return -1
|
|
}
|
|
|
|
variantToTexture := func(format string, variant float64) *Texture {
|
|
textName := fmt.Sprintf(format, variantToInt(variant))
|
|
return ctx.Textures.Texture(textName)
|
|
}
|
|
|
|
stretch := func(x, from, to float64) float64 { return (x - from) * 1 / (to - from) }
|
|
|
|
toPropTexture := func(temp, humid, variant float64) *Texture {
|
|
if temp < .35 {
|
|
if humid < .2 {
|
|
return nil
|
|
} else if humid < .7 {
|
|
return variantToTexture("bush-small-%d", variant*5)
|
|
}
|
|
return variantToTexture("tree-pine-%d", variant*5)
|
|
}
|
|
if temp > .65 {
|
|
if humid < .2 {
|
|
return nil
|
|
}
|
|
if humid < .7 {
|
|
return variantToTexture("cactus-short-%d", variant*7)
|
|
}
|
|
return variantToTexture("cactus-tall-%d", variant*2)
|
|
}
|
|
if humid < .2 {
|
|
return nil
|
|
}
|
|
multiplier := 1 - stretch(humid, 0.2, 1)
|
|
if variant < .5 {
|
|
return variantToTexture("tree-fat-%d", stretch(variant, 0, .5)*multiplier*3)
|
|
} else if variant < .8 {
|
|
return variantToTexture("grass-small-%d", stretch(variant, .5, .8)*multiplier*2)
|
|
}
|
|
return variantToTexture("bush-large-%d", stretch(variant, .8, 1)*multiplier)
|
|
}
|
|
|
|
toItemTexture := func(x, y int32) *Texture {
|
|
variant := terrain.Variant.Value(x, y)
|
|
flower, ok := terrain.Flowers[Pt(x, y)]
|
|
if ok {
|
|
desc, _ := r.game.Herbarium.Find(flower.ID)
|
|
return ctx.Textures.Texture(desc.IconTemplate.Variant(variantToInt(variant)))
|
|
}
|
|
temp := terrain.Temp.Value(x, y)
|
|
humid := terrain.Humid.Value(x, y)
|
|
return toPropTexture(temp, humid, variant)
|
|
}
|
|
|
|
// horizontal: [0, 128) = 128
|
|
// vertical (tile): [96,160) = 64
|
|
// vertical (total): [0,160) = 160
|
|
|
|
r.project.visibleTiles(func(x, y int32, pos Point) {
|
|
text := toTileTexture(x, y)
|
|
rect := r.project.screenToTileRect(pos)
|
|
text.CopyResize(ctx.Renderer, rect)
|
|
|
|
if r.hover != nil && x == r.hover.X && y == r.hover.Y {
|
|
ctx.Textures.Texture("tile-hover").CopyResize(ctx.Renderer, rect)
|
|
}
|
|
})
|
|
|
|
r.project.visibleTiles(func(x, y int32, pos Point) {
|
|
text := toItemTexture(x, y)
|
|
if text == nil {
|
|
return
|
|
}
|
|
|
|
placeX, placeY := terrain.PlaceX.Value(x, y), terrain.PlaceY.Value(x, y)
|
|
pos = r.project.mapToScreenF(float32(x)-.2+float32(.9*placeX-.45), float32(y)-.2+float32(.9*placeY-.45))
|
|
text.CopyResize(ctx.Renderer, r.project.screenToTileRect(pos))
|
|
})
|
|
}
|