Compare commits
No commits in common. "5ebd58249828ee8e95b325193784261e4bf72229" and "a72f4166503c4e2c5e6eb4164fa3be73b133c549" have entirely different histories.
5ebd582498
...
a72f416650
@ -45,8 +45,12 @@ 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) {
|
||||
SetDrawColor(ctx.Renderer, b.Background)
|
||||
ctx.Renderer.SetDrawColor(b.Background.R, b.Background.G, b.Background.B, b.Background.A)
|
||||
ctx.Renderer.FillRect(b.Bounds.SDLPtr())
|
||||
b.Container.Render(ctx)
|
||||
}
|
||||
|
@ -71,27 +71,24 @@ func (b *BuyFlowerButton) Init(ctx *Context) error {
|
||||
return b.updateTexts(ctx)
|
||||
}
|
||||
|
||||
func (b *BuyFlowerButton) Handle(ctx *Context, event sdl.Event) bool {
|
||||
if b.IconButton.Handle(ctx, event) {
|
||||
return true
|
||||
}
|
||||
func (b *BuyFlowerButton) Handle(ctx *Context, event sdl.Event) {
|
||||
b.IconButton.Handle(ctx, event)
|
||||
if b.IsMouseOver && b.hoverAnimation == nil {
|
||||
b.hoverAnimation = NewAnimationPtr(10 * time.Millisecond)
|
||||
b.hoverOffset = b.priceTexture.Size().X
|
||||
} else if !b.IsMouseOver {
|
||||
b.hoverAnimation = nil
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *BuyFlowerButton) Render(ctx *Context) {
|
||||
iconTexture := b.activeTexture(ctx)
|
||||
mouseOverTexture := ctx.Textures.Texture("control-hover")
|
||||
|
||||
pos := Pt(b.Bounds.X, b.Bounds.Y)
|
||||
iconTexture.CopyResize(ctx.Renderer, RectSize(pos.X, pos.Y-60, b.Bounds.W, 120))
|
||||
if (b.IsMouseOver && !b.IsDisabled) || b.IsActive {
|
||||
SetDrawColor(ctx.Renderer, TransparentWhite)
|
||||
ctx.Renderer.FillRect(b.Bounds.SDLPtr())
|
||||
mouseOverTexture.CopyResize(ctx.Renderer, b.Bounds)
|
||||
}
|
||||
|
||||
if b.hoverAnimation != nil {
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
BIN
cmd/tins2020/res/images/game_control_hover.png
Normal file
BIN
cmd/tins2020/res/images/game_control_hover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 297 B |
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
@ -1,11 +1,10 @@
|
||||
control-hover: images/game_control_hover.png
|
||||
control-shovel: images/genericItem_color_022.png
|
||||
control-research: images/genericItem_color_111.png
|
||||
|
||||
control-settings: images/gear.png
|
||||
control-save: images/save.png
|
||||
control-load: images/import.png
|
||||
control-new: images/return.png
|
||||
control-information: images/information.png
|
||||
control-quit: images/power.png
|
||||
|
||||
control-pause: images/pause.png
|
||||
@ -15,9 +14,6 @@ control-run-disabled: images/forward_disabled.png
|
||||
control-run-fast: images/fastForward.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-grass: images/tile_grass.png
|
||||
tile-snow: images/tile_snow.png
|
||||
|
@ -28,7 +28,7 @@ func run() error {
|
||||
}
|
||||
defer sdl.Quit()
|
||||
|
||||
logSDLVersion()
|
||||
// logSDLVersion()
|
||||
|
||||
if err := ttf.Init(); err != nil {
|
||||
return err
|
||||
@ -56,7 +56,7 @@ func run() error {
|
||||
sdl.SetHint(sdl.HINT_RENDER_VSYNC, "1")
|
||||
}
|
||||
sdl.SetHint(sdl.HINT_RENDER_SCALE_QUALITY, "1")
|
||||
window, err := sdl.CreateWindow("Botanim - TINS 2020",
|
||||
window, err := sdl.CreateWindow("TINS 2020",
|
||||
ctx.Settings.Window.Location.X, ctx.Settings.Window.Location.Y,
|
||||
ctx.Settings.Window.Size.X, ctx.Settings.Window.Size.Y,
|
||||
sdl.WINDOW_SHOWN|sdl.WINDOW_RESIZABLE)
|
||||
@ -74,11 +74,10 @@ func run() error {
|
||||
ctx.Init(renderer)
|
||||
|
||||
err = ctx.Fonts.LoadDesc(
|
||||
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: "default", Path: "fonts/OpenSans-Regular.ttf", Size: 16},
|
||||
tins2020.FontDescriptor{Name: "small", Path: "fonts/OpenSans-Regular.ttf", Size: 12},
|
||||
tins2020.FontDescriptor{Name: "title", Path: "fonts/OpenSans-Bold.ttf", Size: 40},
|
||||
tins2020.FontDescriptor{Name: "balance", Path: "fonts/OpenSans-Bold.ttf", Size: 40},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -94,25 +93,18 @@ func run() error {
|
||||
game := tins2020.NewGame()
|
||||
|
||||
app := tins2020.NewContainer()
|
||||
|
||||
overlays := tins2020.NewContainer()
|
||||
dialogs := tins2020.NewDialogs()
|
||||
|
||||
overlays.AddChild(dialogs)
|
||||
overlays.AddChild(&tins2020.FPS{Show: &game.Debug})
|
||||
|
||||
content := tins2020.NewContent(dialogs)
|
||||
content.AddChild(tins2020.NewTerrainRenderer(game))
|
||||
content.AddChild(tins2020.NewGameControls(game, dialogs))
|
||||
|
||||
gameControls := tins2020.NewGameControls(game)
|
||||
overlays.AddChild(gameControls)
|
||||
overlays.AddChild(&tins2020.FPS{})
|
||||
content := tins2020.NewContainer()
|
||||
app.AddChild(content)
|
||||
app.AddChild(overlays)
|
||||
|
||||
content.AddChild(tins2020.NewTerrainRenderer(game))
|
||||
err = app.Init(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dialogs.ShowIntro()
|
||||
|
||||
w, h := window.GetSize()
|
||||
app.Arrange(ctx, tins2020.Rect(0, 0, w, h))
|
||||
|
13
color.go
13
color.go
@ -6,17 +6,4 @@ import (
|
||||
"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 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))
|
||||
}
|
||||
|
11
container.go
11
container.go
@ -25,16 +25,11 @@ func (c *Container) Arrange(ctx *Context, bounds Rectangle) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Container) Handle(ctx *Context, event sdl.Event) bool {
|
||||
if c.ControlBase.Handle(ctx, event) {
|
||||
return true
|
||||
}
|
||||
func (c *Container) Handle(ctx *Context, event sdl.Event) {
|
||||
c.ControlBase.Handle(ctx, event)
|
||||
for _, child := range c.Children {
|
||||
if child.Handle(ctx, event) {
|
||||
return true
|
||||
child.Handle(ctx, event)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Container) Init(ctx *Context) error {
|
||||
|
28
content.go
28
content.go
@ -1,28 +0,0 @@
|
||||
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 {
|
||||
Init(*Context) error
|
||||
Arrange(*Context, Rectangle)
|
||||
Handle(*Context, sdl.Event) bool
|
||||
Handle(*Context, sdl.Event)
|
||||
Render(*Context)
|
||||
}
|
||||
|
||||
@ -31,12 +31,7 @@ func (b *ControlBase) Arrange(ctx *Context, bounds Rectangle) { b.Bounds = bound
|
||||
|
||||
func (b *ControlBase) Init(*Context) error { return nil }
|
||||
|
||||
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) {
|
||||
func (b *ControlBase) Handle(ctx *Context, event sdl.Event) {
|
||||
switch e := event.(type) {
|
||||
case *sdl.MouseMotionEvent:
|
||||
b.IsMouseOver = b.Bounds.IsPointInside(e.X, e.Y)
|
||||
|
53
dialogs.go
53
dialogs.go
@ -1,53 +0,0 @@
|
||||
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,7 +10,6 @@ import (
|
||||
type FPS struct {
|
||||
ControlBase
|
||||
|
||||
Show *bool
|
||||
start time.Time
|
||||
stamp time.Duration
|
||||
slot int
|
||||
@ -26,10 +25,6 @@ func (f *FPS) Init(*Context) error {
|
||||
}
|
||||
|
||||
func (f *FPS) Render(ctx *Context) {
|
||||
if f.Show == nil || !*f.Show {
|
||||
return
|
||||
}
|
||||
|
||||
elapsed := time.Since(f.start)
|
||||
stamp := elapsed / (20 * time.Millisecond)
|
||||
for f.stamp < stamp {
|
||||
|
42
game.go
42
game.go
@ -7,8 +7,6 @@ import (
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
Debug bool
|
||||
|
||||
Balance int
|
||||
Speed GameSpeed
|
||||
SpeedBeforePause GameSpeed
|
||||
@ -31,17 +29,29 @@ const (
|
||||
)
|
||||
|
||||
const simulationInterval = 120 * time.Millisecond
|
||||
const fastSimulationInterval = 20 * time.Millisecond
|
||||
const fastSimulationInterval = 40 * time.Millisecond
|
||||
|
||||
func NewGame() *Game {
|
||||
game := &Game{
|
||||
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{},
|
||||
}
|
||||
herbarium := NewHerbarium()
|
||||
return &Game{
|
||||
Speed: GameSpeedNormal,
|
||||
Balance: 100,
|
||||
Terrain: terrain,
|
||||
Herbarium: herbarium,
|
||||
|
||||
centerChanged: NewEvents(),
|
||||
speedChanged: NewEvents(),
|
||||
toolChanged: NewEvents(),
|
||||
simulation: NewAnimation(time.Millisecond * 10),
|
||||
}
|
||||
game.Reset()
|
||||
return game
|
||||
}
|
||||
|
||||
func (g *Game) selectTool(t Tool) {
|
||||
@ -117,11 +127,6 @@ func (g *Game) Dig(tile Point) {
|
||||
g.Balance += desc.SellPrice
|
||||
}
|
||||
|
||||
func (g *Game) New() {
|
||||
g.Pause()
|
||||
g.Reset()
|
||||
}
|
||||
|
||||
func (g *Game) Load() {
|
||||
g.CancelTool()
|
||||
g.Pause()
|
||||
@ -176,21 +181,6 @@ func (g *Game) PlantFlower(id string, tile Point) {
|
||||
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) Run() { g.setSpeed(GameSpeedNormal) }
|
||||
|
@ -8,7 +8,6 @@ type GameControls struct {
|
||||
Container
|
||||
|
||||
game *Game
|
||||
dialogs *Dialogs
|
||||
|
||||
menu ButtonBar
|
||||
top ButtonBar
|
||||
@ -23,8 +22,8 @@ type GameControls struct {
|
||||
research *IconButton
|
||||
}
|
||||
|
||||
func NewGameControls(game *Game, dialogs *Dialogs) *GameControls {
|
||||
return &GameControls{game: game, dialogs: dialogs}
|
||||
func NewGameControls(game *Game) *GameControls {
|
||||
return &GameControls{game: game}
|
||||
}
|
||||
|
||||
func (c *GameControls) createBuyFlowerButton(id string) *BuyFlowerButton {
|
||||
@ -65,16 +64,6 @@ func (c *GameControls) toolChanged(state interface{}) {
|
||||
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) {
|
||||
c.Bounds = bounds
|
||||
c.menu.Arrange(ctx, RectSize(bounds.X, bounds.Y, buttonBarWidth, bounds.H))
|
||||
@ -86,8 +75,6 @@ func (c *GameControls) Arrange(ctx *Context, bounds Rectangle) {
|
||||
func (c *GameControls) Init(ctx *Context) error {
|
||||
c.game.SpeedChanged().RegisterItf(c.speedChanged)
|
||||
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.ButtonLength = 64
|
||||
@ -117,17 +104,18 @@ func (c *GameControls) Init(ctx *Context) error {
|
||||
|
||||
c.menu.Background = MustHexColor("#356dad")
|
||||
c.menu.Buttons = []Control{
|
||||
NewIconButton("control-settings", func(*Context) { c.dialogs.ShowSettings() }),
|
||||
NewIconButton("control-settings", func(*Context) {}),
|
||||
NewIconButton("control-save", func(*Context) { c.game.Save() }),
|
||||
NewIconButton("control-load", func(ctx *Context) {
|
||||
c.game.Load()
|
||||
c.updateFlowerControls(ctx)
|
||||
for _, b := range c.flowers.Buttons {
|
||||
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 })
|
||||
@ -138,14 +126,11 @@ func (c *GameControls) Init(ctx *Context) error {
|
||||
c.Container.AddChild(&c.top)
|
||||
c.Container.AddChild(&c.flowers)
|
||||
c.Container.AddChild(&c.otherTools)
|
||||
|
||||
return c.Container.Init(ctx)
|
||||
}
|
||||
|
||||
func (c *GameControls) Handle(ctx *Context, event sdl.Event) bool {
|
||||
if c.Container.Handle(ctx, event) {
|
||||
return true
|
||||
}
|
||||
func (c *GameControls) Handle(ctx *Context, event sdl.Event) {
|
||||
c.Container.Handle(ctx, event)
|
||||
|
||||
switch e := event.(type) {
|
||||
case *sdl.KeyboardEvent:
|
||||
@ -163,22 +148,18 @@ func (c *GameControls) Handle(ctx *Context, event sdl.Event) bool {
|
||||
c.game.SelectResearch()
|
||||
case sdl.K_ESCAPE:
|
||||
if c.game.Tool() == nil {
|
||||
c.dialogs.ShowIntro()
|
||||
// TODO: display menu
|
||||
} else {
|
||||
c.game.CancelTool()
|
||||
}
|
||||
return true
|
||||
case sdl.K_F3:
|
||||
c.game.Debug = !c.game.Debug
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *GameControls) Render(ctx *Context) {
|
||||
topBar := MustHexColor("#0000007f")
|
||||
SetDrawColor(ctx.Renderer, topBar)
|
||||
ctx.Renderer.SetDrawColor(topBar.R, topBar.G, topBar.B, topBar.A)
|
||||
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)
|
||||
|
||||
|
@ -1,12 +1,5 @@
|
||||
package tins2020
|
||||
|
||||
type HoverEffect int
|
||||
|
||||
const (
|
||||
HoverEffectLigthen HoverEffect = iota
|
||||
HoverEffectColor
|
||||
)
|
||||
|
||||
type IconButton struct {
|
||||
ControlBase
|
||||
|
||||
@ -16,13 +9,17 @@ type IconButton struct {
|
||||
IconScale Scale
|
||||
IconWidth int32
|
||||
|
||||
IconActive HoverEffect
|
||||
IconHover HoverEffect
|
||||
|
||||
IsActive bool
|
||||
IsDisabled bool
|
||||
}
|
||||
|
||||
type Scale int
|
||||
|
||||
const (
|
||||
ScaleCenter Scale = iota
|
||||
ScaleStretch
|
||||
)
|
||||
|
||||
func NewIconButton(icon string, onClick EventContextFn) *IconButton {
|
||||
return &IconButton{
|
||||
ControlBase: ControlBase{
|
||||
@ -50,11 +47,7 @@ func (b *IconButton) activeTexture(ctx *Context) *Texture {
|
||||
|
||||
func (b *IconButton) Render(ctx *Context) {
|
||||
iconTexture := b.activeTexture(ctx)
|
||||
|
||||
hover := b.IsMouseOver && !b.IsDisabled
|
||||
if (hover && b.IconHover == HoverEffectColor) || (b.IsActive && b.IconActive == HoverEffectColor) {
|
||||
iconTexture.SetColor(MustHexColor("#15569F"))
|
||||
}
|
||||
mouseOverTexture := ctx.Textures.Texture("control-hover")
|
||||
|
||||
if b.IconScale == ScaleCenter {
|
||||
size := iconTexture.Size()
|
||||
@ -67,16 +60,7 @@ func (b *IconButton) Render(ctx *Context) {
|
||||
} else {
|
||||
iconTexture.CopyResize(ctx.Renderer, b.Bounds)
|
||||
}
|
||||
if (hover && b.IconHover == HoverEffectLigthen) || (b.IsActive && b.IconActive == HoverEffectLigthen) {
|
||||
SetDrawColor(ctx.Renderer, TransparentWhite)
|
||||
ctx.Renderer.FillRect(b.Bounds.SDLPtr())
|
||||
if (b.IsMouseOver && !b.IsDisabled) || b.IsActive {
|
||||
mouseOverTexture.CopyResize(ctx.Renderer, b.Bounds)
|
||||
}
|
||||
iconTexture.SetColor(White)
|
||||
}
|
||||
|
||||
type Scale int
|
||||
|
||||
const (
|
||||
ScaleCenter Scale = iota
|
||||
ScaleStretch
|
||||
)
|
||||
|
27
intro.go
27
intro.go
@ -1,27 +0,0 @@
|
||||
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 {
|
||||
return "", err
|
||||
}
|
||||
dir := filepath.Join(config, "tins2020_botanim")
|
||||
dir := filepath.Join(config, "tins2020_flowers_sim")
|
||||
err = os.MkdirAll(dir, 0777)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
108
label.go
108
label.go
@ -1,108 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
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,26 +100,3 @@ 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
37
proxy.go
@ -1,37 +0,0 @@
|
||||
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
|
||||
}
|
||||
|
||||
func (r *terrainRenderer) Handle(ctx *Context, event sdl.Event) bool {
|
||||
func (r *terrainRenderer) Handle(ctx *Context, event sdl.Event) {
|
||||
switch e := event.(type) {
|
||||
case *sdl.MouseButtonEvent:
|
||||
if r.project.windowInteractRect.IsPointInside(e.X, e.Y) {
|
||||
@ -78,10 +78,17 @@ func (r *terrainRenderer) Handle(ctx *Context, event sdl.Event) bool {
|
||||
}
|
||||
case *sdl.MouseWheelEvent:
|
||||
if r.hover != nil {
|
||||
if e.Y < 0 {
|
||||
r.project.ZoomOut(ctx, r.hover.ToPtF())
|
||||
} else {
|
||||
r.project.ZoomIn(ctx, r.hover.ToPtF())
|
||||
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:
|
||||
@ -89,21 +96,7 @@ func (r *terrainRenderer) Handle(ctx *Context, event sdl.Event) bool {
|
||||
r.hover = nil
|
||||
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) {
|
||||
|
@ -44,10 +44,6 @@ func (t *Texture) CopyResize(renderer *sdl.Renderer, dst Rectangle) {
|
||||
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) {
|
||||
// renderer.CopyF(t.texture, t.rect, dst) // Depends on SDL >=2.0.10
|
||||
// }
|
||||
|
Loading…
Reference in New Issue
Block a user