Compare commits
3 Commits
a72f416650
...
5ebd582498
Author | SHA1 | Date | |
---|---|---|---|
5ebd582498 | |||
a6004a8ab6 | |||
9641719579 |
@ -45,12 +45,8 @@ func (b *ButtonBar) Arrange(ctx *Context, bounds Rectangle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ButtonBar) Handle(ctx *Context, event sdl.Event) {
|
|
||||||
b.Container.Handle(ctx, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *ButtonBar) Render(ctx *Context) {
|
func (b *ButtonBar) Render(ctx *Context) {
|
||||||
ctx.Renderer.SetDrawColor(b.Background.R, b.Background.G, b.Background.B, b.Background.A)
|
SetDrawColor(ctx.Renderer, b.Background)
|
||||||
ctx.Renderer.FillRect(b.Bounds.SDLPtr())
|
ctx.Renderer.FillRect(b.Bounds.SDLPtr())
|
||||||
b.Container.Render(ctx)
|
b.Container.Render(ctx)
|
||||||
}
|
}
|
||||||
|
@ -71,24 +71,27 @@ func (b *BuyFlowerButton) Init(ctx *Context) error {
|
|||||||
return b.updateTexts(ctx)
|
return b.updateTexts(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BuyFlowerButton) Handle(ctx *Context, event sdl.Event) {
|
func (b *BuyFlowerButton) Handle(ctx *Context, event sdl.Event) bool {
|
||||||
b.IconButton.Handle(ctx, event)
|
if b.IconButton.Handle(ctx, event) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if b.IsMouseOver && b.hoverAnimation == nil {
|
if b.IsMouseOver && b.hoverAnimation == nil {
|
||||||
b.hoverAnimation = NewAnimationPtr(10 * time.Millisecond)
|
b.hoverAnimation = NewAnimationPtr(10 * time.Millisecond)
|
||||||
b.hoverOffset = b.priceTexture.Size().X
|
b.hoverOffset = b.priceTexture.Size().X
|
||||||
} else if !b.IsMouseOver {
|
} else if !b.IsMouseOver {
|
||||||
b.hoverAnimation = nil
|
b.hoverAnimation = nil
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BuyFlowerButton) Render(ctx *Context) {
|
func (b *BuyFlowerButton) Render(ctx *Context) {
|
||||||
iconTexture := b.activeTexture(ctx)
|
iconTexture := b.activeTexture(ctx)
|
||||||
mouseOverTexture := ctx.Textures.Texture("control-hover")
|
|
||||||
|
|
||||||
pos := Pt(b.Bounds.X, b.Bounds.Y)
|
pos := Pt(b.Bounds.X, b.Bounds.Y)
|
||||||
iconTexture.CopyResize(ctx.Renderer, RectSize(pos.X, pos.Y-60, b.Bounds.W, 120))
|
iconTexture.CopyResize(ctx.Renderer, RectSize(pos.X, pos.Y-60, b.Bounds.W, 120))
|
||||||
if (b.IsMouseOver && !b.IsDisabled) || b.IsActive {
|
if (b.IsMouseOver && !b.IsDisabled) || b.IsActive {
|
||||||
mouseOverTexture.CopyResize(ctx.Renderer, b.Bounds)
|
SetDrawColor(ctx.Renderer, TransparentWhite)
|
||||||
|
ctx.Renderer.FillRect(b.Bounds.SDLPtr())
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.hoverAnimation != nil {
|
if b.hoverAnimation != nil {
|
||||||
|
BIN
cmd/tins2020/res/images/checkmark.png
Normal file
BIN
cmd/tins2020/res/images/checkmark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
cmd/tins2020/res/images/cross.png
Normal file
BIN
cmd/tins2020/res/images/cross.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
Before Width: | Height: | Size: 297 B |
BIN
cmd/tins2020/res/images/information.png
Normal file
BIN
cmd/tins2020/res/images/information.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
cmd/tins2020/res/images/return.png
Normal file
BIN
cmd/tins2020/res/images/return.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
@ -1,10 +1,11 @@
|
|||||||
control-hover: images/game_control_hover.png
|
|
||||||
control-shovel: images/genericItem_color_022.png
|
control-shovel: images/genericItem_color_022.png
|
||||||
control-research: images/genericItem_color_111.png
|
control-research: images/genericItem_color_111.png
|
||||||
|
|
||||||
control-settings: images/gear.png
|
control-settings: images/gear.png
|
||||||
control-save: images/save.png
|
control-save: images/save.png
|
||||||
control-load: images/import.png
|
control-load: images/import.png
|
||||||
|
control-new: images/return.png
|
||||||
|
control-information: images/information.png
|
||||||
control-quit: images/power.png
|
control-quit: images/power.png
|
||||||
|
|
||||||
control-pause: images/pause.png
|
control-pause: images/pause.png
|
||||||
@ -14,6 +15,9 @@ control-run-disabled: images/forward_disabled.png
|
|||||||
control-run-fast: images/fastForward.png
|
control-run-fast: images/fastForward.png
|
||||||
control-run-fast-disabled: images/fastForward_disabled.png
|
control-run-fast-disabled: images/fastForward_disabled.png
|
||||||
|
|
||||||
|
control-cancel: images/cross.png
|
||||||
|
control-confirm: images/checkmark.png
|
||||||
|
|
||||||
tile-dirt: images/tile_dirt.png
|
tile-dirt: images/tile_dirt.png
|
||||||
tile-grass: images/tile_grass.png
|
tile-grass: images/tile_grass.png
|
||||||
tile-snow: images/tile_snow.png
|
tile-snow: images/tile_snow.png
|
||||||
|
@ -28,7 +28,7 @@ func run() error {
|
|||||||
}
|
}
|
||||||
defer sdl.Quit()
|
defer sdl.Quit()
|
||||||
|
|
||||||
// logSDLVersion()
|
logSDLVersion()
|
||||||
|
|
||||||
if err := ttf.Init(); err != nil {
|
if err := ttf.Init(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -56,7 +56,7 @@ func run() error {
|
|||||||
sdl.SetHint(sdl.HINT_RENDER_VSYNC, "1")
|
sdl.SetHint(sdl.HINT_RENDER_VSYNC, "1")
|
||||||
}
|
}
|
||||||
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("Botanim - TINS 2020",
|
||||||
ctx.Settings.Window.Location.X, ctx.Settings.Window.Location.Y,
|
ctx.Settings.Window.Location.X, ctx.Settings.Window.Location.Y,
|
||||||
ctx.Settings.Window.Size.X, ctx.Settings.Window.Size.Y,
|
ctx.Settings.Window.Size.X, ctx.Settings.Window.Size.Y,
|
||||||
sdl.WINDOW_SHOWN|sdl.WINDOW_RESIZABLE)
|
sdl.WINDOW_SHOWN|sdl.WINDOW_RESIZABLE)
|
||||||
@ -74,10 +74,11 @@ func run() error {
|
|||||||
ctx.Init(renderer)
|
ctx.Init(renderer)
|
||||||
|
|
||||||
err = ctx.Fonts.LoadDesc(
|
err = ctx.Fonts.LoadDesc(
|
||||||
tins2020.FontDescriptor{Name: "debug", Path: "fonts/FiraMono-Regular.ttf", Size: 12},
|
|
||||||
tins2020.FontDescriptor{Name: "default", Path: "fonts/OpenSans-Regular.ttf", Size: 16},
|
|
||||||
tins2020.FontDescriptor{Name: "small", Path: "fonts/OpenSans-Regular.ttf", Size: 12},
|
|
||||||
tins2020.FontDescriptor{Name: "balance", Path: "fonts/OpenSans-Bold.ttf", Size: 40},
|
tins2020.FontDescriptor{Name: "balance", Path: "fonts/OpenSans-Bold.ttf", Size: 40},
|
||||||
|
tins2020.FontDescriptor{Name: "debug", Path: "fonts/FiraMono-Regular.ttf", Size: 12},
|
||||||
|
tins2020.FontDescriptor{Name: "default", Path: "fonts/OpenSans-Regular.ttf", Size: 14},
|
||||||
|
tins2020.FontDescriptor{Name: "small", Path: "fonts/OpenSans-Regular.ttf", Size: 12},
|
||||||
|
tins2020.FontDescriptor{Name: "title", Path: "fonts/OpenSans-Bold.ttf", Size: 40},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -93,18 +94,25 @@ func run() error {
|
|||||||
game := tins2020.NewGame()
|
game := tins2020.NewGame()
|
||||||
|
|
||||||
app := tins2020.NewContainer()
|
app := tins2020.NewContainer()
|
||||||
|
|
||||||
overlays := tins2020.NewContainer()
|
overlays := tins2020.NewContainer()
|
||||||
gameControls := tins2020.NewGameControls(game)
|
dialogs := tins2020.NewDialogs()
|
||||||
overlays.AddChild(gameControls)
|
|
||||||
overlays.AddChild(&tins2020.FPS{})
|
overlays.AddChild(dialogs)
|
||||||
content := tins2020.NewContainer()
|
overlays.AddChild(&tins2020.FPS{Show: &game.Debug})
|
||||||
|
|
||||||
|
content := tins2020.NewContent(dialogs)
|
||||||
|
content.AddChild(tins2020.NewTerrainRenderer(game))
|
||||||
|
content.AddChild(tins2020.NewGameControls(game, dialogs))
|
||||||
|
|
||||||
app.AddChild(content)
|
app.AddChild(content)
|
||||||
app.AddChild(overlays)
|
app.AddChild(overlays)
|
||||||
content.AddChild(tins2020.NewTerrainRenderer(game))
|
|
||||||
err = app.Init(ctx)
|
err = app.Init(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
dialogs.ShowIntro()
|
||||||
|
|
||||||
w, h := window.GetSize()
|
w, h := window.GetSize()
|
||||||
app.Arrange(ctx, tins2020.Rect(0, 0, w, h))
|
app.Arrange(ctx, tins2020.Rect(0, 0, w, h))
|
||||||
|
13
color.go
13
color.go
@ -6,4 +6,17 @@ import (
|
|||||||
"github.com/veandco/go-sdl2/sdl"
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var Black = sdl.Color{R: 0, G: 0, B: 0, A: 255}
|
||||||
|
var Transparent = sdl.Color{R: 0, G: 0, B: 0, A: 0}
|
||||||
|
var TransparentWhite = sdl.Color{R: 255, G: 255, B: 255, A: 31}
|
||||||
|
var White = sdl.Color{R: 255, G: 255, B: 255, A: 255}
|
||||||
|
|
||||||
func MustHexColor(s string) sdl.Color { return sdl.Color(img.MustHexColor(s)) }
|
func MustHexColor(s string) sdl.Color { return sdl.Color(img.MustHexColor(s)) }
|
||||||
|
|
||||||
|
func SetDrawColor(renderer *sdl.Renderer, color sdl.Color) {
|
||||||
|
renderer.SetDrawColor(color.R, color.G, color.B, color.A)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetDrawColorHex(renderer *sdl.Renderer, s string) {
|
||||||
|
SetDrawColor(renderer, MustHexColor(s))
|
||||||
|
}
|
||||||
|
13
container.go
13
container.go
@ -25,11 +25,16 @@ func (c *Container) Arrange(ctx *Context, bounds Rectangle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) Handle(ctx *Context, event sdl.Event) {
|
func (c *Container) Handle(ctx *Context, event sdl.Event) bool {
|
||||||
c.ControlBase.Handle(ctx, event)
|
if c.ControlBase.Handle(ctx, event) {
|
||||||
for _, child := range c.Children {
|
return true
|
||||||
child.Handle(ctx, event)
|
|
||||||
}
|
}
|
||||||
|
for _, child := range c.Children {
|
||||||
|
if child.Handle(ctx, event) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) Init(ctx *Context) error {
|
func (c *Container) Init(ctx *Context) error {
|
||||||
|
28
content.go
Normal file
28
content.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package tins2020
|
||||||
|
|
||||||
|
import "github.com/veandco/go-sdl2/sdl"
|
||||||
|
|
||||||
|
// Content shortcuts events when a dialog is opened.
|
||||||
|
type Content struct {
|
||||||
|
Container
|
||||||
|
|
||||||
|
dialogOverlayed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewContent(dialogs *Dialogs) *Content {
|
||||||
|
content := &Content{}
|
||||||
|
dialogs.DialogOpened().Register(func() {
|
||||||
|
content.dialogOverlayed = true
|
||||||
|
})
|
||||||
|
dialogs.DialogClosed().Register(func() {
|
||||||
|
content.dialogOverlayed = false
|
||||||
|
})
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Content) Handle(ctx *Context, event sdl.Event) bool {
|
||||||
|
if c.dialogOverlayed {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return c.Container.Handle(ctx, event)
|
||||||
|
}
|
@ -5,7 +5,7 @@ import "github.com/veandco/go-sdl2/sdl"
|
|||||||
type Control interface {
|
type Control interface {
|
||||||
Init(*Context) error
|
Init(*Context) error
|
||||||
Arrange(*Context, Rectangle)
|
Arrange(*Context, Rectangle)
|
||||||
Handle(*Context, sdl.Event)
|
Handle(*Context, sdl.Event) bool
|
||||||
Render(*Context)
|
Render(*Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +31,12 @@ func (b *ControlBase) Arrange(ctx *Context, bounds Rectangle) { b.Bounds = bound
|
|||||||
|
|
||||||
func (b *ControlBase) Init(*Context) error { return nil }
|
func (b *ControlBase) Init(*Context) error { return nil }
|
||||||
|
|
||||||
func (b *ControlBase) Handle(ctx *Context, event sdl.Event) {
|
func (b *ControlBase) Handle(ctx *Context, event sdl.Event) bool {
|
||||||
|
b.HandleNoFeedback(ctx, event)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *ControlBase) HandleNoFeedback(ctx *Context, event sdl.Event) {
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case *sdl.MouseMotionEvent:
|
case *sdl.MouseMotionEvent:
|
||||||
b.IsMouseOver = b.Bounds.IsPointInside(e.X, e.Y)
|
b.IsMouseOver = b.Bounds.IsPointInside(e.X, e.Y)
|
||||||
|
53
dialogs.go
Normal file
53
dialogs.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package tins2020
|
||||||
|
|
||||||
|
type Dialogs struct {
|
||||||
|
Proxy
|
||||||
|
|
||||||
|
intro Control
|
||||||
|
settings Control
|
||||||
|
|
||||||
|
dialogClosed *Events
|
||||||
|
dialogOpened *Events
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDialogs() *Dialogs {
|
||||||
|
return &Dialogs{
|
||||||
|
dialogClosed: NewEvents(),
|
||||||
|
dialogOpened: NewEvents(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dialogs) DialogClosed() EventHandler { return d.dialogClosed }
|
||||||
|
func (d *Dialogs) DialogOpened() EventHandler { return d.dialogOpened }
|
||||||
|
|
||||||
|
func (d *Dialogs) Init(ctx *Context) error {
|
||||||
|
d.intro = &Intro{}
|
||||||
|
d.settings = &DialogBase{}
|
||||||
|
|
||||||
|
err := d.intro.Init(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = d.settings.Init(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dialogs) Close() {
|
||||||
|
d.Proxied = nil
|
||||||
|
d.dialogClosed.Notify(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dialogs) ShowIntro() {
|
||||||
|
d.Proxied = d.intro
|
||||||
|
d.intro.(Dialog).ShowDialog(d.Close)
|
||||||
|
d.dialogOpened.Notify(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dialogs) ShowSettings() {
|
||||||
|
d.Proxied = d.settings
|
||||||
|
d.settings.(Dialog).ShowDialog(d.Close)
|
||||||
|
d.dialogOpened.Notify(nil)
|
||||||
|
}
|
@ -10,6 +10,7 @@ import (
|
|||||||
type FPS struct {
|
type FPS struct {
|
||||||
ControlBase
|
ControlBase
|
||||||
|
|
||||||
|
Show *bool
|
||||||
start time.Time
|
start time.Time
|
||||||
stamp time.Duration
|
stamp time.Duration
|
||||||
slot int
|
slot int
|
||||||
@ -25,6 +26,10 @@ func (f *FPS) Init(*Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *FPS) Render(ctx *Context) {
|
func (f *FPS) Render(ctx *Context) {
|
||||||
|
if f.Show == nil || !*f.Show {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
elapsed := time.Since(f.start)
|
elapsed := time.Since(f.start)
|
||||||
stamp := elapsed / (20 * time.Millisecond)
|
stamp := elapsed / (20 * time.Millisecond)
|
||||||
for f.stamp < stamp {
|
for f.stamp < stamp {
|
||||||
|
42
game.go
42
game.go
@ -7,6 +7,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Game struct {
|
type Game struct {
|
||||||
|
Debug bool
|
||||||
|
|
||||||
Balance int
|
Balance int
|
||||||
Speed GameSpeed
|
Speed GameSpeed
|
||||||
SpeedBeforePause GameSpeed
|
SpeedBeforePause GameSpeed
|
||||||
@ -29,29 +31,17 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const simulationInterval = 120 * time.Millisecond
|
const simulationInterval = 120 * time.Millisecond
|
||||||
const fastSimulationInterval = 40 * time.Millisecond
|
const fastSimulationInterval = 20 * time.Millisecond
|
||||||
|
|
||||||
func NewGame() *Game {
|
func NewGame() *Game {
|
||||||
terrain := &Map{
|
game := &Game{
|
||||||
Temp: NewNoiseMap(rand.Int63()),
|
|
||||||
Humid: NewNoiseMap(rand.Int63()),
|
|
||||||
Variant: NewRandomNoiseMap(rand.Int63()),
|
|
||||||
PlaceX: NewRandomNoiseMap(rand.Int63()),
|
|
||||||
PlaceY: NewRandomNoiseMap(rand.Int63()),
|
|
||||||
Flowers: map[Point]Flower{},
|
|
||||||
}
|
|
||||||
herbarium := NewHerbarium()
|
|
||||||
return &Game{
|
|
||||||
Speed: GameSpeedNormal,
|
|
||||||
Balance: 100,
|
|
||||||
Terrain: terrain,
|
|
||||||
Herbarium: herbarium,
|
|
||||||
|
|
||||||
centerChanged: NewEvents(),
|
centerChanged: NewEvents(),
|
||||||
speedChanged: NewEvents(),
|
speedChanged: NewEvents(),
|
||||||
toolChanged: NewEvents(),
|
toolChanged: NewEvents(),
|
||||||
simulation: NewAnimation(time.Millisecond * 10),
|
simulation: NewAnimation(time.Millisecond * 10),
|
||||||
}
|
}
|
||||||
|
game.Reset()
|
||||||
|
return game
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Game) selectTool(t Tool) {
|
func (g *Game) selectTool(t Tool) {
|
||||||
@ -127,6 +117,11 @@ func (g *Game) Dig(tile Point) {
|
|||||||
g.Balance += desc.SellPrice
|
g.Balance += desc.SellPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Game) New() {
|
||||||
|
g.Pause()
|
||||||
|
g.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Game) Load() {
|
func (g *Game) Load() {
|
||||||
g.CancelTool()
|
g.CancelTool()
|
||||||
g.Pause()
|
g.Pause()
|
||||||
@ -181,6 +176,21 @@ func (g *Game) PlantFlower(id string, tile Point) {
|
|||||||
g.Terrain.AddFlower(tile, id, flower.Traits)
|
g.Terrain.AddFlower(tile, id, flower.Traits)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Game) Reset() {
|
||||||
|
g.Balance = 100
|
||||||
|
g.Herbarium = NewHerbarium()
|
||||||
|
g.Terrain = &Map{
|
||||||
|
Temp: NewNoiseMap(rand.Int63()),
|
||||||
|
Humid: NewNoiseMap(rand.Int63()),
|
||||||
|
Variant: NewRandomNoiseMap(rand.Int63()),
|
||||||
|
PlaceX: NewRandomNoiseMap(rand.Int63()),
|
||||||
|
PlaceY: NewRandomNoiseMap(rand.Int63()),
|
||||||
|
Flowers: map[Point]Flower{},
|
||||||
|
}
|
||||||
|
g.CancelTool()
|
||||||
|
g.setSpeed(GameSpeedNormal)
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Game) Resume() { g.setSpeed(g.SpeedBeforePause) }
|
func (g *Game) Resume() { g.setSpeed(g.SpeedBeforePause) }
|
||||||
|
|
||||||
func (g *Game) Run() { g.setSpeed(GameSpeedNormal) }
|
func (g *Game) Run() { g.setSpeed(GameSpeedNormal) }
|
||||||
|
@ -8,6 +8,7 @@ type GameControls struct {
|
|||||||
Container
|
Container
|
||||||
|
|
||||||
game *Game
|
game *Game
|
||||||
|
dialogs *Dialogs
|
||||||
|
|
||||||
menu ButtonBar
|
menu ButtonBar
|
||||||
top ButtonBar
|
top ButtonBar
|
||||||
@ -22,8 +23,8 @@ type GameControls struct {
|
|||||||
research *IconButton
|
research *IconButton
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGameControls(game *Game) *GameControls {
|
func NewGameControls(game *Game, dialogs *Dialogs) *GameControls {
|
||||||
return &GameControls{game: game}
|
return &GameControls{game: game, dialogs: dialogs}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GameControls) createBuyFlowerButton(id string) *BuyFlowerButton {
|
func (c *GameControls) createBuyFlowerButton(id string) *BuyFlowerButton {
|
||||||
@ -64,6 +65,16 @@ func (c *GameControls) toolChanged(state interface{}) {
|
|||||||
c.shovel.IsActive = shovel
|
c.shovel.IsActive = shovel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *GameControls) updateFlowerControls(ctx *Context) {
|
||||||
|
for _, b := range c.flowers.Buttons {
|
||||||
|
button := b.(*BuyFlowerButton)
|
||||||
|
flower, ok := c.game.Herbarium.Find(button.FlowerID)
|
||||||
|
if ok {
|
||||||
|
button.Update(ctx, flower)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *GameControls) Arrange(ctx *Context, bounds Rectangle) {
|
func (c *GameControls) Arrange(ctx *Context, bounds Rectangle) {
|
||||||
c.Bounds = bounds
|
c.Bounds = bounds
|
||||||
c.menu.Arrange(ctx, RectSize(bounds.X, bounds.Y, buttonBarWidth, bounds.H))
|
c.menu.Arrange(ctx, RectSize(bounds.X, bounds.Y, buttonBarWidth, bounds.H))
|
||||||
@ -75,6 +86,8 @@ func (c *GameControls) Arrange(ctx *Context, bounds Rectangle) {
|
|||||||
func (c *GameControls) Init(ctx *Context) error {
|
func (c *GameControls) Init(ctx *Context) error {
|
||||||
c.game.SpeedChanged().RegisterItf(c.speedChanged)
|
c.game.SpeedChanged().RegisterItf(c.speedChanged)
|
||||||
c.game.ToolChanged().RegisterItf(c.toolChanged)
|
c.game.ToolChanged().RegisterItf(c.toolChanged)
|
||||||
|
c.dialogs.DialogOpened().Register(func() { c.game.Pause() })
|
||||||
|
c.dialogs.DialogClosed().Register(func() { c.game.Resume() })
|
||||||
|
|
||||||
c.flowers.Background = MustHexColor("#356dad")
|
c.flowers.Background = MustHexColor("#356dad")
|
||||||
c.flowers.ButtonLength = 64
|
c.flowers.ButtonLength = 64
|
||||||
@ -104,18 +117,17 @@ func (c *GameControls) Init(ctx *Context) error {
|
|||||||
|
|
||||||
c.menu.Background = MustHexColor("#356dad")
|
c.menu.Background = MustHexColor("#356dad")
|
||||||
c.menu.Buttons = []Control{
|
c.menu.Buttons = []Control{
|
||||||
NewIconButton("control-settings", func(*Context) {}),
|
NewIconButton("control-settings", func(*Context) { c.dialogs.ShowSettings() }),
|
||||||
NewIconButton("control-save", func(*Context) { c.game.Save() }),
|
NewIconButton("control-save", func(*Context) { c.game.Save() }),
|
||||||
NewIconButton("control-load", func(ctx *Context) {
|
NewIconButton("control-load", func(ctx *Context) {
|
||||||
c.game.Load()
|
c.game.Load()
|
||||||
for _, b := range c.flowers.Buttons {
|
c.updateFlowerControls(ctx)
|
||||||
button := b.(*BuyFlowerButton)
|
|
||||||
flower, ok := c.game.Herbarium.Find(button.FlowerID)
|
|
||||||
if ok {
|
|
||||||
button.Update(ctx, flower)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
|
NewIconButton("control-new", func(ctx *Context) {
|
||||||
|
c.game.New()
|
||||||
|
c.updateFlowerControls(ctx)
|
||||||
|
}),
|
||||||
|
NewIconButton("control-information", func(*Context) { c.dialogs.ShowIntro() }),
|
||||||
}
|
}
|
||||||
|
|
||||||
c.shovel = NewIconButtonConfig("control-shovel", func(*Context) { c.game.SelectShovel() }, func(b *IconButton) { b.IconHeight = 32 })
|
c.shovel = NewIconButtonConfig("control-shovel", func(*Context) { c.game.SelectShovel() }, func(b *IconButton) { b.IconHeight = 32 })
|
||||||
@ -126,11 +138,14 @@ func (c *GameControls) Init(ctx *Context) error {
|
|||||||
c.Container.AddChild(&c.top)
|
c.Container.AddChild(&c.top)
|
||||||
c.Container.AddChild(&c.flowers)
|
c.Container.AddChild(&c.flowers)
|
||||||
c.Container.AddChild(&c.otherTools)
|
c.Container.AddChild(&c.otherTools)
|
||||||
|
|
||||||
return c.Container.Init(ctx)
|
return c.Container.Init(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GameControls) Handle(ctx *Context, event sdl.Event) {
|
func (c *GameControls) Handle(ctx *Context, event sdl.Event) bool {
|
||||||
c.Container.Handle(ctx, event)
|
if c.Container.Handle(ctx, event) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case *sdl.KeyboardEvent:
|
case *sdl.KeyboardEvent:
|
||||||
@ -148,18 +163,22 @@ func (c *GameControls) Handle(ctx *Context, event sdl.Event) {
|
|||||||
c.game.SelectResearch()
|
c.game.SelectResearch()
|
||||||
case sdl.K_ESCAPE:
|
case sdl.K_ESCAPE:
|
||||||
if c.game.Tool() == nil {
|
if c.game.Tool() == nil {
|
||||||
// TODO: display menu
|
c.dialogs.ShowIntro()
|
||||||
} else {
|
} else {
|
||||||
c.game.CancelTool()
|
c.game.CancelTool()
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
|
case sdl.K_F3:
|
||||||
|
c.game.Debug = !c.game.Debug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GameControls) Render(ctx *Context) {
|
func (c *GameControls) Render(ctx *Context) {
|
||||||
topBar := MustHexColor("#0000007f")
|
topBar := MustHexColor("#0000007f")
|
||||||
ctx.Renderer.SetDrawColor(topBar.R, topBar.G, topBar.B, topBar.A)
|
SetDrawColor(ctx.Renderer, topBar)
|
||||||
ctx.Renderer.FillRect(Rect(c.menu.Bounds.Right(), 0, c.flowers.Bounds.X, 64).SDLPtr())
|
ctx.Renderer.FillRect(Rect(c.menu.Bounds.Right(), 0, c.flowers.Bounds.X, 64).SDLPtr())
|
||||||
ctx.Fonts.Font("balance").RenderCopyAlign(ctx.Renderer, FmtMoney(c.game.Balance), Pt(c.top.Bounds.X-8, 58), MustHexColor("#4AC69A"), TextAlignmentRight)
|
ctx.Fonts.Font("balance").RenderCopyAlign(ctx.Renderer, FmtMoney(c.game.Balance), Pt(c.top.Bounds.X-8, 58), MustHexColor("#4AC69A"), TextAlignmentRight)
|
||||||
|
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
package tins2020
|
package tins2020
|
||||||
|
|
||||||
|
type HoverEffect int
|
||||||
|
|
||||||
|
const (
|
||||||
|
HoverEffectLigthen HoverEffect = iota
|
||||||
|
HoverEffectColor
|
||||||
|
)
|
||||||
|
|
||||||
type IconButton struct {
|
type IconButton struct {
|
||||||
ControlBase
|
ControlBase
|
||||||
|
|
||||||
@ -9,17 +16,13 @@ type IconButton struct {
|
|||||||
IconScale Scale
|
IconScale Scale
|
||||||
IconWidth int32
|
IconWidth int32
|
||||||
|
|
||||||
|
IconActive HoverEffect
|
||||||
|
IconHover HoverEffect
|
||||||
|
|
||||||
IsActive bool
|
IsActive bool
|
||||||
IsDisabled bool
|
IsDisabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Scale int
|
|
||||||
|
|
||||||
const (
|
|
||||||
ScaleCenter Scale = iota
|
|
||||||
ScaleStretch
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewIconButton(icon string, onClick EventContextFn) *IconButton {
|
func NewIconButton(icon string, onClick EventContextFn) *IconButton {
|
||||||
return &IconButton{
|
return &IconButton{
|
||||||
ControlBase: ControlBase{
|
ControlBase: ControlBase{
|
||||||
@ -47,7 +50,11 @@ func (b *IconButton) activeTexture(ctx *Context) *Texture {
|
|||||||
|
|
||||||
func (b *IconButton) Render(ctx *Context) {
|
func (b *IconButton) Render(ctx *Context) {
|
||||||
iconTexture := b.activeTexture(ctx)
|
iconTexture := b.activeTexture(ctx)
|
||||||
mouseOverTexture := ctx.Textures.Texture("control-hover")
|
|
||||||
|
hover := b.IsMouseOver && !b.IsDisabled
|
||||||
|
if (hover && b.IconHover == HoverEffectColor) || (b.IsActive && b.IconActive == HoverEffectColor) {
|
||||||
|
iconTexture.SetColor(MustHexColor("#15569F"))
|
||||||
|
}
|
||||||
|
|
||||||
if b.IconScale == ScaleCenter {
|
if b.IconScale == ScaleCenter {
|
||||||
size := iconTexture.Size()
|
size := iconTexture.Size()
|
||||||
@ -60,7 +67,16 @@ func (b *IconButton) Render(ctx *Context) {
|
|||||||
} else {
|
} else {
|
||||||
iconTexture.CopyResize(ctx.Renderer, b.Bounds)
|
iconTexture.CopyResize(ctx.Renderer, b.Bounds)
|
||||||
}
|
}
|
||||||
if (b.IsMouseOver && !b.IsDisabled) || b.IsActive {
|
if (hover && b.IconHover == HoverEffectLigthen) || (b.IsActive && b.IconActive == HoverEffectLigthen) {
|
||||||
mouseOverTexture.CopyResize(ctx.Renderer, b.Bounds)
|
SetDrawColor(ctx.Renderer, TransparentWhite)
|
||||||
|
ctx.Renderer.FillRect(b.Bounds.SDLPtr())
|
||||||
}
|
}
|
||||||
|
iconTexture.SetColor(White)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Scale int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ScaleCenter Scale = iota
|
||||||
|
ScaleStretch
|
||||||
|
)
|
||||||
|
27
intro.go
Normal file
27
intro.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package tins2020
|
||||||
|
|
||||||
|
type Intro struct {
|
||||||
|
LargeDialog
|
||||||
|
|
||||||
|
welcome Paragraph
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Intro) Init(ctx *Context) error {
|
||||||
|
i.welcome.Text =
|
||||||
|
"Welcome to Botanim!\n\n" +
|
||||||
|
"In Botanim you play the role of botanist and your goal is to cultivate flowers in an open landscape.\n\n" +
|
||||||
|
"Flowers can only grow (well) in certain climates based on two properties: humidity and temperature. Watch out for existing vegetation to get an idea how humid the land is and check the appearance of the tile to see how hot it is. When well placed your planted flower will spread soon but an odd choice might kill your flower almost instantly. So choose carefully. When the flower spread significantly you can dig up flowers again to collect more money.\n\n" +
|
||||||
|
"Controls:\n" +
|
||||||
|
" - D: Selects shovel\n" +
|
||||||
|
" - R: Selects research\n" +
|
||||||
|
" - Spacebar: pauses game\n" +
|
||||||
|
" - 1: runs game at normal speed\n" +
|
||||||
|
" - 2: runs game extra fast\n" +
|
||||||
|
" - Mouse wheel or plus/minus: zooms landscape\n" +
|
||||||
|
" - CTRL + left mouse button or middle mouse button: pans landscape\n" +
|
||||||
|
"\n" +
|
||||||
|
"Have fun playing!"
|
||||||
|
i.SetContent(&i.welcome)
|
||||||
|
|
||||||
|
return i.LargeDialog.Init(ctx)
|
||||||
|
}
|
2
io.go
2
io.go
@ -33,7 +33,7 @@ func UserDir() (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
dir := filepath.Join(config, "tins2020_flowers_sim")
|
dir := filepath.Join(config, "tins2020_botanim")
|
||||||
err = os.MkdirAll(dir, 0777)
|
err = os.MkdirAll(dir, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
108
label.go
Normal file
108
label.go
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package tins2020
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Label struct {
|
||||||
|
ControlBase
|
||||||
|
|
||||||
|
FontColor sdl.Color
|
||||||
|
FontName string
|
||||||
|
Text string
|
||||||
|
Alignment TextAlignment
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Label) fontColor() sdl.Color {
|
||||||
|
var none sdl.Color
|
||||||
|
if l.FontColor == none {
|
||||||
|
return MustHexColor("#ffffff")
|
||||||
|
}
|
||||||
|
return l.FontColor
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Label) fontName() string {
|
||||||
|
if len(l.FontName) == 0 {
|
||||||
|
return "default"
|
||||||
|
}
|
||||||
|
return l.FontName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Label) Render(ctx *Context) {
|
||||||
|
font := ctx.Fonts.Font(l.fontName())
|
||||||
|
color := l.fontColor()
|
||||||
|
bottom := l.Bounds.Y + l.Bounds.H
|
||||||
|
switch l.Alignment {
|
||||||
|
case TextAlignmentCenter:
|
||||||
|
font.RenderCopyAlign(ctx.Renderer, l.Text, Pt(l.Bounds.X+l.Bounds.W/2, bottom), color, TextAlignmentCenter)
|
||||||
|
case TextAlignmentLeft:
|
||||||
|
font.RenderCopyAlign(ctx.Renderer, l.Text, Pt(l.Bounds.X, bottom), color, TextAlignmentLeft)
|
||||||
|
case TextAlignmentRight:
|
||||||
|
font.RenderCopyAlign(ctx.Renderer, l.Text, Pt(l.Bounds.X+l.Bounds.W, bottom), color, TextAlignmentRight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Paragraph struct {
|
||||||
|
Label
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (p *Paragraph) Arrange(ctx *Context, bounds Rectangle) {
|
||||||
|
// p.Label.Arrange(ctx, bounds)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (p *Paragraph) Render(ctx *Context) {
|
||||||
|
font := ctx.Fonts.Font(p.fontName())
|
||||||
|
color := p.fontColor()
|
||||||
|
fontHeight := int32(font.Height())
|
||||||
|
lines := strings.Split(p.Text, "\n")
|
||||||
|
|
||||||
|
measure := func(s string) int32 {
|
||||||
|
w, _, _ := font.SizeUTF8(s)
|
||||||
|
return int32(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
spaces := func(s string) []int {
|
||||||
|
var spaces []int
|
||||||
|
offset := 0
|
||||||
|
for {
|
||||||
|
space := strings.Index(s[offset:], " ")
|
||||||
|
if space == -1 {
|
||||||
|
return spaces
|
||||||
|
}
|
||||||
|
offset += space
|
||||||
|
spaces = append(spaces, offset)
|
||||||
|
offset++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fit := func(s string) string {
|
||||||
|
if measure(s) < p.Bounds.W {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
spaces := spaces(s)
|
||||||
|
for split := len(spaces) - 1; split >= 0; split-- {
|
||||||
|
clipped := s[:spaces[split]]
|
||||||
|
if measure(clipped) < p.Bounds.W {
|
||||||
|
return clipped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := p.Bounds.Y
|
||||||
|
for _, line := range lines {
|
||||||
|
if len(line) == 0 {
|
||||||
|
offset += fontHeight
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for len(line) > 0 {
|
||||||
|
offset += fontHeight
|
||||||
|
clipped := fit(line)
|
||||||
|
line = strings.TrimLeft(line[len(clipped):], " ")
|
||||||
|
font.RenderCopy(ctx.Renderer, clipped, Pt(p.Bounds.X, offset), color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
95
largedialog.go
Normal file
95
largedialog.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package tins2020
|
||||||
|
|
||||||
|
import "github.com/veandco/go-sdl2/sdl"
|
||||||
|
|
||||||
|
type DialogBase struct {
|
||||||
|
Container
|
||||||
|
|
||||||
|
content Proxy
|
||||||
|
close EventFn
|
||||||
|
}
|
||||||
|
|
||||||
|
type Dialog interface {
|
||||||
|
CloseDialog()
|
||||||
|
ShowDialog(EventFn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DialogBase) CloseDialog() {
|
||||||
|
close := d.close
|
||||||
|
if close != nil {
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DialogBase) SetContent(control Control) {
|
||||||
|
d.content.Proxied = control
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DialogBase) ShowDialog(close EventFn) {
|
||||||
|
d.close = close
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DialogBase) Init(ctx *Context) error {
|
||||||
|
d.AddChild(&d.content)
|
||||||
|
return d.Container.Init(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
type LargeDialog struct {
|
||||||
|
DialogBase
|
||||||
|
|
||||||
|
title Label
|
||||||
|
close IconButton
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *LargeDialog) Arrange(ctx *Context, bounds Rectangle) {
|
||||||
|
const titleHeight = 64
|
||||||
|
d.ControlBase.Arrange(ctx, bounds)
|
||||||
|
d.title.Arrange(ctx, RectSize(bounds.X, bounds.Y, bounds.W, titleHeight))
|
||||||
|
d.close.Arrange(ctx, RectSize(bounds.W-64, 0, 64, 64))
|
||||||
|
d.content.Arrange(ctx, RectSize(bounds.X+titleHeight, 96, bounds.W-2*titleHeight, bounds.H-titleHeight))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *LargeDialog) Init(ctx *Context) error {
|
||||||
|
d.title = Label{
|
||||||
|
Text: "Botanim",
|
||||||
|
FontName: "title",
|
||||||
|
Alignment: TextAlignmentCenter,
|
||||||
|
}
|
||||||
|
d.close = IconButton{
|
||||||
|
Icon: "control-cancel",
|
||||||
|
IconHover: HoverEffectColor,
|
||||||
|
IconWidth: 32,
|
||||||
|
}
|
||||||
|
d.close.OnLeftMouseButtonClick = EmptyEvent(d.CloseDialog)
|
||||||
|
d.AddChild(&d.title)
|
||||||
|
d.AddChild(&d.close)
|
||||||
|
return d.DialogBase.Init(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *LargeDialog) Handle(ctx *Context, event sdl.Event) bool {
|
||||||
|
if d.DialogBase.Handle(ctx, event) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e := event.(type) {
|
||||||
|
case *sdl.KeyboardEvent:
|
||||||
|
if e.Type == sdl.KEYDOWN {
|
||||||
|
switch e.Keysym.Sym {
|
||||||
|
case sdl.K_ESCAPE:
|
||||||
|
d.CloseDialog()
|
||||||
|
return true
|
||||||
|
case sdl.K_RETURN:
|
||||||
|
d.CloseDialog()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *LargeDialog) Render(ctx *Context) {
|
||||||
|
SetDrawColor(ctx.Renderer, MustHexColor("#356DAD"))
|
||||||
|
ctx.Renderer.FillRect(d.Bounds.SDLPtr())
|
||||||
|
|
||||||
|
d.DialogBase.Render(ctx)
|
||||||
|
}
|
@ -100,3 +100,26 @@ func (p *projection) visibleTiles(action func(int32, int32, Point)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *projection) ZoomOut(ctx *Context, center PointF) {
|
||||||
|
if p.zoom <= .25 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.SetZoom(ctx, center, .5*p.zoom)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *projection) ZoomIn(ctx *Context, center PointF) {
|
||||||
|
if p.zoom >= 2 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.SetZoom(ctx, center, 2*p.zoom)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *projection) SetZoom(ctx *Context, center PointF, zoom float32) {
|
||||||
|
if p.zoom == zoom {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.center = center.Sub(center.Sub(p.center).Mul(p.zoom / zoom))
|
||||||
|
p.zoom = zoom
|
||||||
|
p.update(ctx.Renderer)
|
||||||
|
}
|
||||||
|
37
proxy.go
Normal file
37
proxy.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package tins2020
|
||||||
|
|
||||||
|
import "github.com/veandco/go-sdl2/sdl"
|
||||||
|
|
||||||
|
var _ Control = &Proxy{}
|
||||||
|
|
||||||
|
type Proxy struct {
|
||||||
|
Proxied Control
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Proxy) Arrange(ctx *Context, bounds Rectangle) {
|
||||||
|
if p.Proxied == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.Proxied.Arrange(ctx, bounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Proxy) Handle(ctx *Context, event sdl.Event) bool {
|
||||||
|
if p.Proxied == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return p.Proxied.Handle(ctx, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Proxy) Init(ctx *Context) error {
|
||||||
|
if p.Proxied == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.Proxied.Init(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Proxy) Render(ctx *Context) {
|
||||||
|
if p.Proxied == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.Proxied.Render(ctx)
|
||||||
|
}
|
@ -37,7 +37,7 @@ func isControlKeyDown() bool {
|
|||||||
return state[sdl.SCANCODE_LCTRL] == 1 || state[sdl.SCANCODE_RCTRL] == 1
|
return state[sdl.SCANCODE_LCTRL] == 1 || state[sdl.SCANCODE_RCTRL] == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *terrainRenderer) Handle(ctx *Context, event sdl.Event) {
|
func (r *terrainRenderer) Handle(ctx *Context, event sdl.Event) bool {
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case *sdl.MouseButtonEvent:
|
case *sdl.MouseButtonEvent:
|
||||||
if r.project.windowInteractRect.IsPointInside(e.X, e.Y) {
|
if r.project.windowInteractRect.IsPointInside(e.X, e.Y) {
|
||||||
@ -78,17 +78,10 @@ func (r *terrainRenderer) Handle(ctx *Context, event sdl.Event) {
|
|||||||
}
|
}
|
||||||
case *sdl.MouseWheelEvent:
|
case *sdl.MouseWheelEvent:
|
||||||
if r.hover != nil {
|
if r.hover != nil {
|
||||||
zoom := r.project.zoom
|
if e.Y < 0 {
|
||||||
if e.Y < 0 && r.project.zoom > .25 {
|
r.project.ZoomOut(ctx, r.hover.ToPtF())
|
||||||
zoom *= .5
|
} else {
|
||||||
} else if e.Y > 0 && r.project.zoom < 2 {
|
r.project.ZoomIn(ctx, r.hover.ToPtF())
|
||||||
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:
|
case *sdl.WindowEvent:
|
||||||
@ -96,7 +89,21 @@ func (r *terrainRenderer) Handle(ctx *Context, event sdl.Event) {
|
|||||||
r.hover = nil
|
r.hover = nil
|
||||||
r.project.update(ctx.Renderer)
|
r.project.update(ctx.Renderer)
|
||||||
}
|
}
|
||||||
|
case *sdl.KeyboardEvent:
|
||||||
|
if e.Type == sdl.KEYDOWN {
|
||||||
|
switch e.Keysym.Sym {
|
||||||
|
case sdl.K_PLUS:
|
||||||
|
r.project.ZoomIn(ctx, r.project.center)
|
||||||
|
case sdl.K_KP_PLUS:
|
||||||
|
r.project.ZoomIn(ctx, r.project.center)
|
||||||
|
case sdl.K_MINUS:
|
||||||
|
r.project.ZoomOut(ctx, r.project.center)
|
||||||
|
case sdl.K_KP_MINUS:
|
||||||
|
r.project.ZoomOut(ctx, r.project.center)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *terrainRenderer) Render(ctx *Context) {
|
func (r *terrainRenderer) Render(ctx *Context) {
|
||||||
|
@ -44,6 +44,10 @@ func (t *Texture) CopyResize(renderer *sdl.Renderer, dst Rectangle) {
|
|||||||
t.CopyPartResize(renderer, Rect(0, 0, t.size.X, t.size.Y), dst)
|
t.CopyPartResize(renderer, Rect(0, 0, t.size.X, t.size.Y), dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Texture) SetColor(color sdl.Color) {
|
||||||
|
t.texture.SetColorMod(color.R, color.G, color.B)
|
||||||
|
}
|
||||||
|
|
||||||
// func (t *Texture) CopyF(renderer *sdl.Renderer, dst *sdl.FRect) {
|
// func (t *Texture) CopyF(renderer *sdl.Renderer, dst *sdl.FRect) {
|
||||||
// renderer.CopyF(t.texture, t.rect, dst) // Depends on SDL >=2.0.10
|
// renderer.CopyF(t.texture, t.rect, dst) // Depends on SDL >=2.0.10
|
||||||
// }
|
// }
|
||||||
|
Loading…
Reference in New Issue
Block a user