Compare commits
No commits in common. "2413c7d3d4125d9bf3d7b502b136cd47a6dc6e6b" and "27afe594fe59c38651fa7959b63b561d2d9f829d" have entirely different histories.
2413c7d3d4
...
27afe594fe
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.0 KiB |
@ -1,74 +0,0 @@
|
|||||||
|
|
||||||
tile-dirt: images/tile_dirt.png
|
|
||||||
tile-grass: images/tile_grass.png
|
|
||||||
tile-snow: images/tile_snow.png
|
|
||||||
|
|
||||||
cactus-small-1: images/cactus_short_NE.png
|
|
||||||
cactus-small-2: images/cactus_short_NW.png
|
|
||||||
cactus-small-3: images/cactus_short_SW.png
|
|
||||||
cactus-small-4: images/cactus_short_SE.png
|
|
||||||
|
|
||||||
cactus-tall-1: images/cactus_tall_NE.png
|
|
||||||
cactus-tall-2: images/cactus_tall_NW.png
|
|
||||||
cactus-tall-3: images/cactus_tall_SW.png
|
|
||||||
cactus-tall-4: images/cactus_tall_SE.png
|
|
||||||
|
|
||||||
tree-fat-1: images/tree_fat_NE.png
|
|
||||||
tree-fat-2: images/tree_fat_NW.png
|
|
||||||
tree-fat-3: images/tree_fat_SW.png
|
|
||||||
tree-fat-4: images/tree_fat_SE.png
|
|
||||||
|
|
||||||
tree-pine-1: images/tree_pineDefaultA_NE.png
|
|
||||||
tree-pine-2: images/tree_pineDefaultA_NW.png
|
|
||||||
tree-pine-3: images/tree_pineDefaultA_SW.png
|
|
||||||
tree-pine-4: images/tree_pineDefaultA_SE.png
|
|
||||||
|
|
||||||
grass-small-1: images/grass_NE.png
|
|
||||||
grass-small-2: images/grass_NW.png
|
|
||||||
grass-small-3: images/grass_SW.png
|
|
||||||
grass-small-4: images/grass_SE.png
|
|
||||||
|
|
||||||
grass-leafs-1: images/grass_leafs_NE.png
|
|
||||||
grass-leafs-2: images/grass_leafs_NW.png
|
|
||||||
grass-leafs-3: images/grass_leafs_SW.png
|
|
||||||
grass-leafs-4: images/grass_leafs_SE.png
|
|
||||||
|
|
||||||
bush-small-1: images/plant_bushSmall_NE.png
|
|
||||||
bush-small-2: images/plant_bushSmall_NW.png
|
|
||||||
bush-small-3: images/plant_bushSmall_SW.png
|
|
||||||
bush-small-4: images/plant_bushSmall_SE.png
|
|
||||||
|
|
||||||
bush-large-1: images/plant_bushLarge_NE.png
|
|
||||||
bush-large-2: images/plant_bushLarge_NW.png
|
|
||||||
bush-large-3: images/plant_bushLarge_SW.png
|
|
||||||
bush-large-4: images/plant_bushLarge_SE.png
|
|
||||||
|
|
||||||
bush-large-1: images/plant_bushLarge_NE.png
|
|
||||||
bush-large-2: images/plant_bushLarge_NW.png
|
|
||||||
bush-large-3: images/plant_bushLarge_SW.png
|
|
||||||
bush-large-4: images/plant_bushLarge_SE.png
|
|
||||||
|
|
||||||
flower-poppy-1: images/flower_yellowC_NE.png
|
|
||||||
flower-poppy-2: images/flower_yellowC_NW.png
|
|
||||||
flower-poppy-3: images/flower_yellowC_SW.png
|
|
||||||
flower-poppy-4: images/flower_yellowC_SE.png
|
|
||||||
|
|
||||||
flower-red-c-1: images/flower_redC_NE.png
|
|
||||||
flower-red-c-2: images/flower_redC_NW.png
|
|
||||||
flower-red-c-3: images/flower_redC_SW.png
|
|
||||||
flower-red-c-4: images/flower_redC_SE.png
|
|
||||||
|
|
||||||
flower-red-a-1: images/flower_redA_NE.png
|
|
||||||
flower-red-a-2: images/flower_redA_NW.png
|
|
||||||
flower-red-a-3: images/flower_redA_SW.png
|
|
||||||
flower-red-a-4: images/flower_redA_SE.png
|
|
||||||
|
|
||||||
flower-purple-a-1: images/flower_purpleA_NE.png
|
|
||||||
flower-purple-a-2: images/flower_purpleA_NW.png
|
|
||||||
flower-purple-a-3: images/flower_purpleA_SW.png
|
|
||||||
flower-purple-a-4: images/flower_purpleA_SE.png
|
|
||||||
|
|
||||||
flower-purple-c-1: images/flower_purpleC_NE.png
|
|
||||||
flower-purple-c-2: images/flower_purpleC_NW.png
|
|
||||||
flower-purple-c-3: images/flower_purpleC_SW.png
|
|
||||||
flower-purple-c-4: images/flower_purpleC_SE.png
|
|
@ -47,18 +47,10 @@ func run() error {
|
|||||||
Y: sdl.WINDOWPOS_UNDEFINED,
|
Y: sdl.WINDOWPOS_UNDEFINED,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ctx.Settings.Window.Size == nil {
|
|
||||||
ctx.Settings.Window.Size = &tins2020.Point{
|
|
||||||
X: 800,
|
|
||||||
Y: 600,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sdl.SetHint(sdl.HINT_RENDER_SCALE_QUALITY, "1")
|
sdl.SetHint(sdl.HINT_RENDER_SCALE_QUALITY, "1")
|
||||||
window, err := sdl.CreateWindow("TINS 2020",
|
window, err := sdl.CreateWindow("TINS 2020", ctx.Settings.Window.Location.X, ctx.Settings.Window.Location.Y,
|
||||||
ctx.Settings.Window.Location.X, ctx.Settings.Window.Location.Y,
|
800, 600, sdl.WINDOW_SHOWN|sdl.WINDOW_RESIZABLE)
|
||||||
ctx.Settings.Window.Size.X, ctx.Settings.Window.Size.Y,
|
|
||||||
sdl.WINDOW_SHOWN|sdl.WINDOW_RESIZABLE)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -72,31 +64,62 @@ func run() error {
|
|||||||
|
|
||||||
ctx.Init(renderer)
|
ctx.Init(renderer)
|
||||||
|
|
||||||
err = ctx.Fonts.LoadDesc(
|
err = ctx.Fonts.Load("default", "fonts/OpenSans-Regular.ttf", 12)
|
||||||
tins2020.FontDescriptor{Name: "debug", Path: "fonts/OpenSans-Regular.ttf", Size: 12},
|
|
||||||
tins2020.FontDescriptor{Name: "default", Path: "fonts/FiraMono-Regular.ttf", Size: 10},
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
textureLoader := tins2020.NewResourceLoader()
|
err = ctx.Textures.Load(
|
||||||
err = textureLoader.LoadFromFile(&ctx.Resources, "textures.txt", func(name, content string) error {
|
"tile-dirt", "images/tile_dirt.png",
|
||||||
return ctx.Textures.Load(name, content)
|
"tile-grass", "images/tile_grass.png",
|
||||||
})
|
"tile-snow", "images/tile_snow.png",
|
||||||
|
|
||||||
|
"cactus-small-1", "images/cactus_short_NE.png",
|
||||||
|
"cactus-small-2", "images/cactus_short_NW.png",
|
||||||
|
"cactus-small-3", "images/cactus_short_SW.png",
|
||||||
|
"cactus-small-4", "images/cactus_short_SE.png",
|
||||||
|
|
||||||
|
"cactus-tall-1", "images/cactus_tall_NE.png",
|
||||||
|
"cactus-tall-2", "images/cactus_tall_NW.png",
|
||||||
|
"cactus-tall-3", "images/cactus_tall_SW.png",
|
||||||
|
"cactus-tall-4", "images/cactus_tall_SE.png",
|
||||||
|
|
||||||
|
"tree-fat-1", "images/tree_fat_NE.png",
|
||||||
|
"tree-fat-2", "images/tree_fat_NW.png",
|
||||||
|
"tree-fat-3", "images/tree_fat_SW.png",
|
||||||
|
"tree-fat-4", "images/tree_fat_SE.png",
|
||||||
|
|
||||||
|
"tree-pine-1", "images/tree_pineDefaultA_NE.png",
|
||||||
|
"tree-pine-2", "images/tree_pineDefaultA_NW.png",
|
||||||
|
"tree-pine-3", "images/tree_pineDefaultA_SW.png",
|
||||||
|
"tree-pine-4", "images/tree_pineDefaultA_SE.png",
|
||||||
|
|
||||||
|
"grass-small-1", "images/grass_NE.png",
|
||||||
|
"grass-small-2", "images/grass_NW.png",
|
||||||
|
"grass-small-3", "images/grass_SW.png",
|
||||||
|
"grass-small-4", "images/grass_SE.png",
|
||||||
|
|
||||||
|
"grass-leafs-1", "images/grass_leafs_NE.png",
|
||||||
|
"grass-leafs-2", "images/grass_leafs_NW.png",
|
||||||
|
"grass-leafs-3", "images/grass_leafs_SW.png",
|
||||||
|
"grass-leafs-4", "images/grass_leafs_SE.png",
|
||||||
|
|
||||||
|
"bush-small-1", "images/plant_bushSmall_NE.png",
|
||||||
|
"bush-small-2", "images/plant_bushSmall_NW.png",
|
||||||
|
"bush-small-3", "images/plant_bushSmall_SW.png",
|
||||||
|
"bush-small-4", "images/plant_bushSmall_SE.png",
|
||||||
|
|
||||||
|
"bush-large-1", "images/plant_bushLarge_NE.png",
|
||||||
|
"bush-large-2", "images/plant_bushLarge_NW.png",
|
||||||
|
"bush-large-3", "images/plant_bushLarge_SW.png",
|
||||||
|
"bush-large-4", "images/plant_bushLarge_SE.png",
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
game := tins2020.NewGame()
|
game := tins2020.NewGame()
|
||||||
|
control := tins2020.NewTerrainRenderer(game.Terrain)
|
||||||
app := tins2020.NewContainer()
|
err = control.Init(ctx)
|
||||||
overlays := tins2020.NewContainer()
|
|
||||||
overlays.AddChild(&tins2020.FPS{})
|
|
||||||
content := tins2020.NewContainer()
|
|
||||||
app.AddChild(content)
|
|
||||||
app.AddChild(overlays)
|
|
||||||
content.AddChild(tins2020.NewTerrainRenderer(game.Terrain))
|
|
||||||
err = app.Init(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -112,9 +135,6 @@ func run() error {
|
|||||||
case sdl.WINDOWEVENT_MOVED:
|
case sdl.WINDOWEVENT_MOVED:
|
||||||
x, y := window.GetPosition()
|
x, y := window.GetPosition()
|
||||||
ctx.Settings.Window.Location = &tins2020.Point{X: x, Y: y}
|
ctx.Settings.Window.Location = &tins2020.Point{X: x, Y: y}
|
||||||
case sdl.WINDOWEVENT_SIZE_CHANGED:
|
|
||||||
w, h := window.GetSize()
|
|
||||||
ctx.Settings.Window.Size = &tins2020.Point{X: w, Y: h}
|
|
||||||
}
|
}
|
||||||
case *sdl.KeyboardEvent:
|
case *sdl.KeyboardEvent:
|
||||||
switch e.Keysym.Sym {
|
switch e.Keysym.Sym {
|
||||||
@ -122,9 +142,8 @@ func run() error {
|
|||||||
ctx.Quit()
|
ctx.Quit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.Handle(ctx, event)
|
control.Handle(ctx, event)
|
||||||
}
|
}
|
||||||
game.Update()
|
|
||||||
|
|
||||||
if ctx.ShouldQuit {
|
if ctx.ShouldQuit {
|
||||||
break
|
break
|
||||||
@ -132,7 +151,7 @@ func run() error {
|
|||||||
|
|
||||||
renderer.SetDrawColor(0, 0, 0, 255)
|
renderer.SetDrawColor(0, 0, 0, 255)
|
||||||
renderer.Clear()
|
renderer.Clear()
|
||||||
app.Render(ctx)
|
control.Render(ctx)
|
||||||
renderer.Present()
|
renderer.Present()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
39
container.go
@ -1,39 +0,0 @@
|
|||||||
package tins2020
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Container struct {
|
|
||||||
Children []Control
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewContainer() *Container {
|
|
||||||
return &Container{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Container) AddChild(child Control) {
|
|
||||||
c.Children = append(c.Children, child)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Container) Handle(ctx *Context, event sdl.Event) {
|
|
||||||
for _, child := range c.Children {
|
|
||||||
child.Handle(ctx, event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Container) Render(ctx *Context) {
|
|
||||||
for _, child := range c.Children {
|
|
||||||
child.Render(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Container) Init(ctx *Context) error {
|
|
||||||
for _, child := range c.Children {
|
|
||||||
err := child.Init(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
18
control.go
@ -1,18 +0,0 @@
|
|||||||
package tins2020
|
|
||||||
|
|
||||||
import "github.com/veandco/go-sdl2/sdl"
|
|
||||||
|
|
||||||
type Control interface {
|
|
||||||
Init(*Context) error
|
|
||||||
Handle(*Context, sdl.Event)
|
|
||||||
Render(*Context)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ControlBase struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *ControlBase) Handle(*Context, sdl.Event) {}
|
|
||||||
|
|
||||||
func (b *ControlBase) Render(*Context) {}
|
|
||||||
|
|
||||||
func (b *ControlBase) Init(*Context) error { return nil }
|
|
46
flower.go
@ -1,46 +0,0 @@
|
|||||||
package tins2020
|
|
||||||
|
|
||||||
type Flower struct {
|
|
||||||
Traits FlowerTraits
|
|
||||||
}
|
|
||||||
|
|
||||||
type FlowerTraits struct {
|
|
||||||
Spread float32
|
|
||||||
Life float32
|
|
||||||
LifeModifier float32
|
|
||||||
Resistance FlowerResistance
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *FlowerTraits) UpdateModifier(temp, humid float32) {
|
|
||||||
mod := float32(1)
|
|
||||||
cold := temp * 2
|
|
||||||
mod *= Min32(1, Sqrt32(t.Resistance.Cold*t.Resistance.Cold+cold*cold))
|
|
||||||
hot := (1 - temp) * 2
|
|
||||||
mod *= Min32(1, Sqrt32(t.Resistance.Hot*t.Resistance.Hot+hot*hot))
|
|
||||||
dry := humid * 2
|
|
||||||
mod *= Min32(1, Sqrt32(t.Resistance.Dry*t.Resistance.Dry+dry*dry))
|
|
||||||
wet := (1 - humid) * 2
|
|
||||||
mod *= Min32(1, Sqrt32(t.Resistance.Wet*t.Resistance.Wet+wet*wet))
|
|
||||||
t.LifeModifier = mod
|
|
||||||
}
|
|
||||||
|
|
||||||
type FlowerResistance struct {
|
|
||||||
Cold float32 // 0 will die almost instantly, 1 is completely resistant.
|
|
||||||
Hot float32
|
|
||||||
Dry float32
|
|
||||||
Wet float32
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
Resistance: FlowerResistance{
|
|
||||||
Cold: 0.3,
|
|
||||||
Hot: 0.3,
|
|
||||||
Dry: 0.3,
|
|
||||||
Wet: 0.3,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
54
fonts.go
@ -1,66 +1,18 @@
|
|||||||
package tins2020
|
package tins2020
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
|
||||||
"github.com/veandco/go-sdl2/ttf"
|
"github.com/veandco/go-sdl2/ttf"
|
||||||
"opslag.de/schobers/fs/vfs"
|
"opslag.de/schobers/fs/vfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Font struct {
|
|
||||||
*ttf.Font
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Font) Render(renderer *sdl.Renderer, text string, pos Point, color sdl.Color) (*Texture, error) {
|
|
||||||
surface, err := f.RenderUTF8Solid(text, color)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer surface.Free()
|
|
||||||
texture, err := NewTextureFromSurface(renderer, surface)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return texture, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Font) RenderCopy(renderer *sdl.Renderer, text string, pos Point, color sdl.Color) error {
|
|
||||||
texture, err := f.Render(renderer, text, pos, color)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer texture.Destroy()
|
|
||||||
texture.Copy(renderer, texture.RectOffset(pos))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Fonts struct {
|
type Fonts struct {
|
||||||
dir vfs.CopyDir
|
dir vfs.CopyDir
|
||||||
fonts map[string]*Font
|
fonts map[string]*ttf.Font
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Fonts) Init(dir vfs.CopyDir) {
|
func (f *Fonts) Init(dir vfs.CopyDir) {
|
||||||
f.dir = dir
|
f.dir = dir
|
||||||
f.fonts = map[string]*Font{}
|
f.fonts = map[string]*ttf.Font{}
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fonts) Font(name string) *Font { return f.fonts[name] }
|
|
||||||
|
|
||||||
type FontDescriptor struct {
|
|
||||||
Name string
|
|
||||||
Path string
|
|
||||||
Size int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fonts) LoadDesc(fonts ...FontDescriptor) error {
|
|
||||||
for _, desc := range fonts {
|
|
||||||
err := f.Load(desc.Name, desc.Path, desc.Size)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error loading '%s'; error: %v", desc.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Fonts) Load(name, path string, size int) error {
|
func (f *Fonts) Load(name, path string, size int) error {
|
||||||
@ -75,7 +27,7 @@ func (f *Fonts) Load(name, path string, size int) error {
|
|||||||
if font, ok := f.fonts[name]; ok {
|
if font, ok := f.fonts[name]; ok {
|
||||||
font.Close()
|
font.Close()
|
||||||
}
|
}
|
||||||
f.fonts[name] = &Font{font}
|
f.fonts[name] = font
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
package tins2020
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FPS struct {
|
|
||||||
ControlBase
|
|
||||||
|
|
||||||
start time.Time
|
|
||||||
stamp time.Duration
|
|
||||||
slot int
|
|
||||||
ticks []int
|
|
||||||
total int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FPS) Init(*Context) error {
|
|
||||||
f.start = time.Now()
|
|
||||||
f.stamp = 0
|
|
||||||
f.ticks = make([]int, 51)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FPS) Render(ctx *Context) {
|
|
||||||
elapsed := time.Since(f.start)
|
|
||||||
stamp := elapsed / (20 * time.Millisecond)
|
|
||||||
for f.stamp < stamp {
|
|
||||||
f.total += f.ticks[f.slot]
|
|
||||||
f.slot = (f.slot + 1) % len(f.ticks)
|
|
||||||
f.total -= f.ticks[f.slot]
|
|
||||||
f.ticks[f.slot] = 0
|
|
||||||
f.stamp++
|
|
||||||
}
|
|
||||||
f.ticks[f.slot]++
|
|
||||||
|
|
||||||
font := ctx.Fonts.Font("debug")
|
|
||||||
font.RenderCopy(ctx.Renderer, fmt.Sprintf("FPS: %d", f.total), Pt(5, 5), sdl.Color{R: 255, G: 255, B: 255, A: 255})
|
|
||||||
}
|
|
109
game.go
@ -2,15 +2,14 @@ package tins2020
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
|
||||||
|
"opslag.de/schobers/geom/noise"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Game struct {
|
type Game struct {
|
||||||
Money int
|
|
||||||
Terrain *Map
|
Terrain *Map
|
||||||
|
Flowers []Flower
|
||||||
start time.Time
|
Bees []Bee
|
||||||
lastUpdate time.Duration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Map struct {
|
type Map struct {
|
||||||
@ -19,21 +18,55 @@ type Map struct {
|
|||||||
Variant NoiseMap
|
Variant NoiseMap
|
||||||
PlaceX NoiseMap // displacement map of props
|
PlaceX NoiseMap // displacement map of props
|
||||||
PlaceY NoiseMap
|
PlaceY NoiseMap
|
||||||
|
|
||||||
Flowers map[Point]Flower
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Map) AddFlower(pos Point, traits FlowerTraits) {
|
type NoiseMap interface {
|
||||||
m.Flowers[pos] = m.NewFlower(pos, traits)
|
Value(x, y int32) float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Map) NewFlower(pos Point, traits FlowerTraits) Flower {
|
func NewNoiseMap(seed int64) NoiseMap {
|
||||||
flower := Flower{
|
return &noiseMap{
|
||||||
Traits: traits,
|
noise: noise.NewPerlin(seed),
|
||||||
|
alpha: 2,
|
||||||
|
beta: 4,
|
||||||
|
harmonics: 2,
|
||||||
}
|
}
|
||||||
temp, humid := float32(m.Temp.Value(pos.X, pos.Y)), float32(m.Humid.Value(pos.X, pos.Y))
|
}
|
||||||
flower.Traits.UpdateModifier(temp, humid)
|
|
||||||
return flower
|
func NewRandomNoiseMap(seed int64) NoiseMap {
|
||||||
|
return &randomNoiseMap{noise.NewPerlin(seed)}
|
||||||
|
}
|
||||||
|
|
||||||
|
type noiseMap struct {
|
||||||
|
noise *noise.Perlin
|
||||||
|
alpha, beta float64
|
||||||
|
harmonics int
|
||||||
|
}
|
||||||
|
|
||||||
|
func clipNormalized(x float64) float64 {
|
||||||
|
if x < 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if x > 1 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value generates the noise value for an x/y pair. The range of the output is approximately [-1.325825214,1.325825214] (for 4 harmonics).
|
||||||
|
func (m *noiseMap) Value(x, y int32) float64 {
|
||||||
|
value := m.noise.Noise2D(float64(x)*.01, float64(y)*.01, m.alpha, m.beta, m.harmonics)*.565 + .5
|
||||||
|
return clipNormalized(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
type randomNoiseMap struct {
|
||||||
|
*noise.Perlin
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value generates the noise value for an x/y pair. The range of the output is approximately [-1.325825214,1.325825214] (for 4 harmonics).
|
||||||
|
func (m randomNoiseMap) Value(x, y int32) float64 {
|
||||||
|
value := m.Noise2D(float64(x)*.53, float64(y)*.53, 1.01, 2, 2)*.5 + .5
|
||||||
|
return clipNormalized(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGame() *Game {
|
func NewGame() *Game {
|
||||||
@ -43,52 +76,18 @@ func NewGame() *Game {
|
|||||||
Variant: NewRandomNoiseMap(rand.Int63()),
|
Variant: NewRandomNoiseMap(rand.Int63()),
|
||||||
PlaceX: NewRandomNoiseMap(rand.Int63()),
|
PlaceX: NewRandomNoiseMap(rand.Int63()),
|
||||||
PlaceY: NewRandomNoiseMap(rand.Int63()),
|
PlaceY: NewRandomNoiseMap(rand.Int63()),
|
||||||
Flowers: map[Point]Flower{},
|
|
||||||
}
|
}
|
||||||
terrain.AddFlower(Pt(0, 0), NewPoppyTraits())
|
|
||||||
return &Game{
|
return &Game{
|
||||||
Money: 100,
|
|
||||||
Terrain: terrain,
|
Terrain: terrain,
|
||||||
|
Flowers: []Flower{},
|
||||||
start: time.Now(),
|
Bees: []Bee{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Game) Update() {
|
type Flower struct {
|
||||||
update := time.Since(g.start)
|
Location PointF
|
||||||
for g.lastUpdate < update {
|
|
||||||
g.tick()
|
|
||||||
g.lastUpdate += time.Millisecond * 10
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Game) tick() {
|
type Bee struct {
|
||||||
randomNeighbor := func(pos Point) Point {
|
Location PointF
|
||||||
switch rand.Intn(4) {
|
|
||||||
case 0:
|
|
||||||
return Pt(pos.X-1, pos.Y)
|
|
||||||
case 1:
|
|
||||||
return Pt(pos.X, pos.Y-1)
|
|
||||||
case 2:
|
|
||||||
return Pt(pos.X+1, pos.Y)
|
|
||||||
case 3:
|
|
||||||
return Pt(pos.X, pos.Y+1)
|
|
||||||
}
|
|
||||||
return pos
|
|
||||||
}
|
|
||||||
flowers := map[Point]Flower{}
|
|
||||||
for pos, flower := range g.Terrain.Flowers {
|
|
||||||
if rand.Float32() < flower.Traits.Spread {
|
|
||||||
dst := randomNeighbor(pos)
|
|
||||||
if _, ok := g.Terrain.Flowers[dst]; !ok {
|
|
||||||
if _, ok := flowers[dst]; !ok {
|
|
||||||
flowers[dst] = g.Terrain.NewFlower(dst, flower.Traits)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if rand.Float32() < flower.Traits.Life*flower.Traits.LifeModifier {
|
|
||||||
flowers[pos] = flower
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.Terrain.Flowers = flowers
|
|
||||||
}
|
}
|
||||||
|
37
math.go
@ -1,37 +0,0 @@
|
|||||||
package tins2020
|
|
||||||
|
|
||||||
import "math"
|
|
||||||
|
|
||||||
func Abs32(x float32) float32 {
|
|
||||||
if x < 0 {
|
|
||||||
return -x
|
|
||||||
}
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
func AbsSub32(a, b float32) float32 {
|
|
||||||
if a > b {
|
|
||||||
return a - b
|
|
||||||
}
|
|
||||||
return b - a
|
|
||||||
}
|
|
||||||
|
|
||||||
func Ceil32(x float32) float32 { return float32(math.Ceil(float64(x))) }
|
|
||||||
|
|
||||||
func Floor32(x float32) float32 { return float32(math.Floor(float64(x))) }
|
|
||||||
|
|
||||||
func Max32(a, b float32) float32 {
|
|
||||||
if a > b {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func Min32(a, b float32) float32 {
|
|
||||||
if a < b {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func Sqrt32(x float32) float32 { return float32(math.Sqrt(float64(x))) }
|
|
52
noisemap.go
@ -1,52 +0,0 @@
|
|||||||
package tins2020
|
|
||||||
|
|
||||||
import "opslag.de/schobers/geom/noise"
|
|
||||||
|
|
||||||
type NoiseMap interface {
|
|
||||||
Value(x, y int32) float64
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewNoiseMap(seed int64) NoiseMap {
|
|
||||||
return &noiseMap{
|
|
||||||
noise: noise.NewPerlin(seed),
|
|
||||||
alpha: 2,
|
|
||||||
beta: 4,
|
|
||||||
harmonics: 2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRandomNoiseMap(seed int64) NoiseMap {
|
|
||||||
return &randomNoiseMap{noise.NewPerlin(seed)}
|
|
||||||
}
|
|
||||||
|
|
||||||
type noiseMap struct {
|
|
||||||
noise *noise.Perlin
|
|
||||||
alpha, beta float64
|
|
||||||
harmonics int
|
|
||||||
}
|
|
||||||
|
|
||||||
func clipNormalized(x float64) float64 {
|
|
||||||
if x < 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if x > 1 {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value generates the noise value for an x/y pair. The range of the output is approximately [-1.325825214,1.325825214] (for 4 harmonics).
|
|
||||||
func (m *noiseMap) Value(x, y int32) float64 {
|
|
||||||
value := m.noise.Noise2D(float64(x)*.01, float64(y)*.01, m.alpha, m.beta, m.harmonics)*.565 + .5
|
|
||||||
return clipNormalized(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
type randomNoiseMap struct {
|
|
||||||
*noise.Perlin
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value generates the noise value for an x/y pair. The range of the output is approximately [-1.325825214,1.325825214] (for 4 harmonics).
|
|
||||||
func (m randomNoiseMap) Value(x, y int32) float64 {
|
|
||||||
value := m.Noise2D(float64(x)*.53, float64(y)*.53, 1.01, 2, 2)*.5 + .5
|
|
||||||
return clipNormalized(value)
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
package tins2020
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type projection struct {
|
|
||||||
center PointF
|
|
||||||
zoom float32
|
|
||||||
zoomInv float32
|
|
||||||
|
|
||||||
windowRect sdl.Rect
|
|
||||||
tileScreenDelta PointF
|
|
||||||
tileScreenDeltaInv PointF
|
|
||||||
tileScreenOffset Point
|
|
||||||
tileScreenSize Point
|
|
||||||
tileFitScreenSize Point
|
|
||||||
windowCenter Point
|
|
||||||
}
|
|
||||||
|
|
||||||
func newProjection() projection {
|
|
||||||
return projection{zoom: 1, tileScreenDelta: PtF(65, 32), tileScreenDeltaInv: PtF(1./65, 1./32)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *projection) mapToScreen(x, y int32) Point {
|
|
||||||
return p.mapToScreenF(float32(x), float32(y))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *projection) mapToScreenF(x, y float32) Point {
|
|
||||||
translated := PtF(x-p.center.X, y-p.center.Y)
|
|
||||||
return Pt(p.windowCenter.X+int32((translated.X-translated.Y)*65*p.zoomInv), p.windowCenter.Y+int32((translated.X+translated.Y)*32*p.zoomInv))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *projection) screenToMap(x, y int32) PointF {
|
|
||||||
pos := p.screenToMapRel(x-p.windowCenter.X, y-p.windowCenter.Y)
|
|
||||||
return p.center.Add(pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *projection) screenToMapRel(x, y int32) PointF {
|
|
||||||
normX := p.zoom * float32(x)
|
|
||||||
normY := p.zoom * float32(y)
|
|
||||||
return PtF(.5*(p.tileScreenDeltaInv.X*normX+p.tileScreenDeltaInv.Y*normY), .5*(-p.tileScreenDeltaInv.X*normX+p.tileScreenDeltaInv.Y*normY))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *projection) screenToTileFitRect(pos Point) *sdl.Rect {
|
|
||||||
return &sdl.Rect{X: pos.X - p.tileFitScreenSize.X, Y: pos.Y - p.tileFitScreenSize.Y, W: 2 * p.tileFitScreenSize.X, H: 2 * p.tileFitScreenSize.Y}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *projection) screenToTileRect(pos Point) *sdl.Rect {
|
|
||||||
return &sdl.Rect{X: pos.X - p.tileScreenOffset.X, Y: pos.Y - p.tileScreenOffset.Y, W: p.tileScreenSize.X, H: p.tileScreenSize.Y}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *projection) update(renderer *sdl.Renderer) {
|
|
||||||
p.zoomInv = 1 / p.zoom
|
|
||||||
|
|
||||||
p.tileScreenOffset = Pt(int32(p.zoomInv*256), int32(p.zoomInv*300))
|
|
||||||
p.tileScreenSize = Pt(int32(p.zoomInv*512), int32(p.zoomInv*512))
|
|
||||||
p.tileFitScreenSize = Pt(int32(p.zoomInv*65), int32(p.zoomInv*32))
|
|
||||||
|
|
||||||
windowW, windowH, err := renderer.GetOutputSize()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
p.windowCenter = Pt(windowW/2, windowH/2)
|
|
||||||
p.windowRect = sdl.Rect{X: 0, Y: 0, W: windowW - 0, H: windowH - 0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *projection) visibleTiles(action func(int32, int32, Point)) {
|
|
||||||
topLeft := p.screenToMap(p.windowRect.X, p.windowRect.Y)
|
|
||||||
topRight := p.screenToMap(p.windowRect.X+p.windowRect.W, p.windowRect.Y)
|
|
||||||
bottomLeft := p.screenToMap(p.windowRect.X, p.windowRect.Y+p.windowRect.H)
|
|
||||||
bottomRight := p.screenToMap(p.windowRect.X+p.windowRect.W, p.windowRect.Y+p.windowRect.H)
|
|
||||||
minY, maxY := int32(Floor32(topRight.Y)), int32(Ceil32(bottomLeft.Y))
|
|
||||||
minX, maxX := int32(Floor32(topLeft.X)), int32(Ceil32(bottomRight.X))
|
|
||||||
for y := minY; y <= maxY; y++ {
|
|
||||||
for x := minX; x <= maxX; x++ {
|
|
||||||
pos := p.mapToScreen(x, y)
|
|
||||||
rectFit := p.screenToTileFitRect(pos)
|
|
||||||
if rectFit.X+rectFit.W < p.windowRect.X || rectFit.Y+rectFit.H < p.windowRect.Y {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if rectFit.X > p.windowRect.X+p.windowRect.W || rectFit.Y > p.windowRect.Y+p.windowRect.H {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
action(x, y, pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
9
renderer.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package tins2020
|
||||||
|
|
||||||
|
import "github.com/veandco/go-sdl2/sdl"
|
||||||
|
|
||||||
|
type Control interface {
|
||||||
|
Init(*Context) error
|
||||||
|
Handle(*Context, sdl.Event)
|
||||||
|
Render(*Context)
|
||||||
|
}
|
@ -1,51 +0,0 @@
|
|||||||
package tins2020
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ResourceLoader struct {
|
|
||||||
Resources map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewResourceLoader() *ResourceLoader {
|
|
||||||
return &ResourceLoader{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *ResourceLoader) parseResourcesFile(res *Resources, name string) error {
|
|
||||||
f, err := res.Fs().Open(name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
l.Resources = map[string]string{}
|
|
||||||
scanner := bufio.NewScanner(f)
|
|
||||||
for scanner.Scan() {
|
|
||||||
definition := scanner.Text()
|
|
||||||
sep := strings.Index(definition, ":")
|
|
||||||
if sep == -1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
name := strings.TrimSpace(definition[:sep])
|
|
||||||
content := strings.TrimSpace(definition[sep+1:])
|
|
||||||
l.Resources[name] = content
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *ResourceLoader) LoadFromFile(res *Resources, name string, action func(string, string) error) error {
|
|
||||||
err := l.parseResourcesFile(res, name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for name, content := range l.Resources {
|
|
||||||
err = action(name, content)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot load resource '%s'; error: %v", name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -31,5 +31,4 @@ func (s *Settings) Store() error {
|
|||||||
|
|
||||||
type WindowSettings struct {
|
type WindowSettings struct {
|
||||||
Location *Point
|
Location *Point
|
||||||
Size *Point
|
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,11 @@ package tins2020
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"opslag.de/schobers/geom"
|
||||||
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
"opslag.de/schobers/geom"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type terrainRenderer struct {
|
type terrainRenderer struct {
|
||||||
@ -21,6 +23,59 @@ type interaction struct {
|
|||||||
mouseDrag *Point
|
mouseDrag *Point
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type projection struct {
|
||||||
|
center PointF
|
||||||
|
zoom float32
|
||||||
|
zoomInv float32
|
||||||
|
|
||||||
|
tileScreenDelta PointF
|
||||||
|
tileScreenDeltaInv PointF
|
||||||
|
tileScreenOffset Point
|
||||||
|
tileScreenSize Point
|
||||||
|
windowCenter Point
|
||||||
|
}
|
||||||
|
|
||||||
|
func newProjection() projection {
|
||||||
|
return projection{zoom: 1, tileScreenDelta: PtF(65, 32), tileScreenDeltaInv: PtF(1./65, 1./32)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *projection) update(renderer *sdl.Renderer) {
|
||||||
|
p.zoomInv = 1 / p.zoom
|
||||||
|
|
||||||
|
p.tileScreenOffset = Pt(int32(p.zoomInv*256), int32(p.zoomInv*300))
|
||||||
|
p.tileScreenSize = Pt(int32(p.zoomInv*512), int32(p.zoomInv*512))
|
||||||
|
|
||||||
|
windowW, windowH, err := renderer.GetOutputSize()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
p.windowCenter = Pt(windowW/2, windowH/2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *projection) mapToScreen(x, y int32) Point {
|
||||||
|
return p.mapToScreenF(float32(x), float32(y))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *projection) mapToScreenF(x, y float32) Point {
|
||||||
|
translated := PtF(x-p.center.X, y-p.center.Y)
|
||||||
|
return Pt(p.windowCenter.X+int32((translated.X-translated.Y)*65*p.zoomInv), p.windowCenter.Y+int32((translated.X+translated.Y)*32*p.zoomInv))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *projection) screenToMapRel(x, y int32) PointF {
|
||||||
|
normX := p.zoom * float32(x)
|
||||||
|
normY := p.zoom * float32(y)
|
||||||
|
return PtF(.5*(p.tileScreenDeltaInv.X*normX+p.tileScreenDeltaInv.Y*normY), .5*(-p.tileScreenDeltaInv.X*normX+p.tileScreenDeltaInv.Y*normY))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *projection) screenToMap(x, y int32) PointF {
|
||||||
|
pos := p.screenToMapRel(x-p.windowCenter.X, y-p.windowCenter.Y)
|
||||||
|
return p.center.Add(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *projection) screenToTileRect(pos Point) *sdl.Rect {
|
||||||
|
return &sdl.Rect{X: pos.X - p.tileScreenOffset.X, Y: pos.Y - p.tileScreenOffset.Y, W: p.tileScreenSize.X, H: p.tileScreenSize.Y}
|
||||||
|
}
|
||||||
|
|
||||||
func NewTerrainRenderer(terrain *Map) Control {
|
func NewTerrainRenderer(terrain *Map) Control {
|
||||||
return &terrainRenderer{terrain: terrain, project: newProjection()}
|
return &terrainRenderer{terrain: terrain, project: newProjection()}
|
||||||
}
|
}
|
||||||
@ -37,22 +92,25 @@ func (r *terrainRenderer) Handle(ctx *Context, event sdl.Event) {
|
|||||||
r.interact.mouseLeftDown = e.Type == sdl.MOUSEBUTTONDOWN
|
r.interact.mouseLeftDown = e.Type == sdl.MOUSEBUTTONDOWN
|
||||||
if r.interact.mouseLeftDown && r.interact.mouseDrag == nil {
|
if r.interact.mouseLeftDown && r.interact.mouseDrag == nil {
|
||||||
r.interact.mouseDrag = &Point{e.X, e.Y}
|
r.interact.mouseDrag = &Point{e.X, e.Y}
|
||||||
|
fmt.Println("Drag start", r.interact.mouseDrag)
|
||||||
} else if !r.interact.mouseLeftDown && r.interact.mouseDrag != nil {
|
} else if !r.interact.mouseLeftDown && r.interact.mouseDrag != nil {
|
||||||
|
fmt.Println("Drag end", r.interact.mouseDrag)
|
||||||
r.interact.mouseDrag = nil
|
r.interact.mouseDrag = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *sdl.MouseMotionEvent:
|
case *sdl.MouseMotionEvent:
|
||||||
r.hover = r.project.screenToMap(e.X, e.Y)
|
r.hover = r.project.screenToMap(e.X, e.Y)
|
||||||
if r.interact.mouseDrag != nil {
|
if r.interact.mouseDrag != nil {
|
||||||
|
fmt.Println("Dragging...", r.project.center)
|
||||||
r.project.center = r.project.center.Sub(r.project.screenToMapRel(e.X-r.interact.mouseDrag.X, e.Y-r.interact.mouseDrag.Y))
|
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)
|
r.project.update(ctx.Renderer)
|
||||||
r.interact.mouseDrag = &Point{e.X, e.Y}
|
r.interact.mouseDrag = &Point{e.X, e.Y}
|
||||||
}
|
}
|
||||||
case *sdl.MouseWheelEvent:
|
case *sdl.MouseWheelEvent:
|
||||||
if e.Y > 0 && r.project.zoom > .5 {
|
if e.Y > 0 {
|
||||||
r.project.zoom *= .5
|
r.project.zoom *= .5
|
||||||
r.project.update(ctx.Renderer)
|
r.project.update(ctx.Renderer)
|
||||||
} else if e.Y < 0 && r.project.zoom < 4 {
|
} else if e.Y < 0 {
|
||||||
r.project.zoom *= 2
|
r.project.zoom *= 2
|
||||||
r.project.update(ctx.Renderer)
|
r.project.update(ctx.Renderer)
|
||||||
}
|
}
|
||||||
@ -127,48 +185,41 @@ func (r *terrainRenderer) Render(ctx *Context) {
|
|||||||
return variantToTexture("bush-large-%d", stretch(variant, .8, 1)*multiplier)
|
return variantToTexture("bush-large-%d", stretch(variant, .8, 1)*multiplier)
|
||||||
}
|
}
|
||||||
|
|
||||||
toItemTexture := func(x, y int32) *Texture {
|
|
||||||
variant := r.terrain.Variant.Value(x, y)
|
|
||||||
_, ok := r.terrain.Flowers[Pt(x, y)]
|
|
||||||
if ok {
|
|
||||||
return variantToTexture("flower-poppy-%d", variant)
|
|
||||||
}
|
|
||||||
temp := r.terrain.Temp.Value(x, y)
|
|
||||||
humid := r.terrain.Humid.Value(x, y)
|
|
||||||
return toPropTexture(temp, humid, variant)
|
|
||||||
}
|
|
||||||
|
|
||||||
// horizontal: [191, 321) = 130
|
// horizontal: [191, 321) = 130
|
||||||
// vertical: [267,332) = 65
|
// vertical: [267,332) = 65
|
||||||
|
|
||||||
hover := Pt(int32(geom.Round32(r.hover.X)), int32(geom.Round32(r.hover.Y)))
|
hover := Pt(int32(geom.Round32(r.hover.X)), int32(geom.Round32(r.hover.Y)))
|
||||||
r.project.visibleTiles(func(x, y int32, pos Point) {
|
for y := int32(-100); y < 100; y++ {
|
||||||
if x == hover.X && y == hover.Y {
|
for x := int32(-100); x < 100; x++ {
|
||||||
return
|
if x == hover.X && y == hover.Y {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
temp := r.terrain.Temp.Value(x, y)
|
||||||
|
humid := r.terrain.Humid.Value(x, y)
|
||||||
|
text := toTileTexture(temp, humid)
|
||||||
|
pos := r.project.mapToScreen(x, y)
|
||||||
|
text.Copy(ctx.Renderer, r.project.screenToTileRect(pos))
|
||||||
}
|
}
|
||||||
temp := r.terrain.Temp.Value(x, y)
|
}
|
||||||
humid := r.terrain.Humid.Value(x, y)
|
|
||||||
text := toTileTexture(temp, humid)
|
|
||||||
rect := r.project.screenToTileRect(pos)
|
|
||||||
text.Copy(ctx.Renderer, rect)
|
|
||||||
})
|
|
||||||
|
|
||||||
r.project.visibleTiles(func(x, y int32, pos Point) {
|
for y := int32(-100); y < 100; y++ {
|
||||||
text := toItemTexture(x, y)
|
for x := int32(-100); x < 100; x++ {
|
||||||
if text == nil {
|
variant := r.terrain.Variant.Value(x, y)
|
||||||
return
|
if variant < -1 || variant > 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
temp := r.terrain.Temp.Value(x, y)
|
||||||
|
humid := r.terrain.Humid.Value(x, y)
|
||||||
|
text := toPropTexture(temp, humid, variant)
|
||||||
|
if text == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
placeX, placeY := r.terrain.PlaceX.Value(x, y), r.terrain.PlaceY.Value(x, y)
|
||||||
|
pos := r.project.mapToScreenF(float32(x)-.2+float32(.8*placeX-.4), float32(y)-.2+float32(.8*placeY-.4))
|
||||||
|
|
||||||
|
text.Copy(ctx.Renderer, r.project.screenToTileRect(pos))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
placeX, placeY := r.terrain.PlaceX.Value(x, y), r.terrain.PlaceY.Value(x, y)
|
|
||||||
pos = r.project.mapToScreenF(float32(x)-.2+float32(.8*placeX-.4), float32(y)-.2+float32(.8*placeY-.4))
|
|
||||||
text.Copy(ctx.Renderer, r.project.screenToTileRect(pos))
|
|
||||||
})
|
|
||||||
|
|
||||||
// gfx.RectangleColor(ctx.Renderer, r.project.windowRect.X, r.project.windowRect.Y, r.project.windowRect.X+r.project.windowRect.W, r.project.windowRect.Y+r.project.windowRect.H, sdl.Color{R: 255, A: 255})
|
|
||||||
// for y := int32(-40); y < 40; y++ {
|
|
||||||
// for x := int32(-40); x < 40; x++ {
|
|
||||||
// pos := r.project.mapToScreen(x, y)
|
|
||||||
// ctx.Fonts.Font("debug").RenderCopy(ctx.Renderer, fmt.Sprintf("(%d, %d)", x, y), pos, sdl.Color{R: 255, A: 255})
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,6 @@ func NewTextureFromSurface(renderer *sdl.Renderer, surface *sdl.Surface) (*Textu
|
|||||||
|
|
||||||
func (t *Texture) Rect() *sdl.Rect { return t.rect }
|
func (t *Texture) Rect() *sdl.Rect { return t.rect }
|
||||||
|
|
||||||
func (t *Texture) RectOffset(offset Point) *sdl.Rect {
|
|
||||||
return &sdl.Rect{X: offset.X, Y: offset.Y, W: t.rect.W, H: t.rect.H}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Texture) Copy(renderer *sdl.Renderer, target *sdl.Rect) {
|
func (t *Texture) Copy(renderer *sdl.Renderer, target *sdl.Rect) {
|
||||||
renderer.Copy(t.texture, t.rect, target)
|
renderer.Copy(t.texture, t.rect, target)
|
||||||
}
|
}
|
||||||
|