diff --git a/TODO.md b/TODO.md index d7279c3..137ee49 100644 --- a/TODO.md +++ b/TODO.md @@ -1,16 +1,18 @@ - add all other options like size etc -- Clear screen problem: - - it works when hitting the K key, immediately - - its being turned off correctly when entering menu and on when leaving it - - but regardless of the setting, after turning it off, the engine - seems to run a couple of ticks with the old setting before switching - scenes - - looks like a race condition - - obviously with K there are more loops before actually switching - scenes, which doesn't happen with ESC - - - if grid lines is disabled, they appear anyway in the first frame (then disappear) - changing options mid-game has no effect in most cases, even after a restart + +- RLE file loading works but pattern is barely visible + +- Statefile loading does not work correclty anymore. With larger grids + everything is empty. With square grids part of the grid is cut + off. Smaller grids load though + +- Same thing with RLE files: with smaller grid size, RLE file shows, + but with larger (or default) grid size, its invisible + +- gridlines vanish if starting in menu mode, after starting a + game. They are there in all manual modes and on startup before + leaving the menu diff --git a/config.go b/config.go index ecdb97d..3729a3d 100644 --- a/config.go +++ b/config.go @@ -8,7 +8,6 @@ import ( "strconv" "strings" - "github.com/alecthomas/repr" "github.com/spf13/pflag" "github.com/tlinden/golsky/rle" ) @@ -30,6 +29,7 @@ type Config struct { Restart, RestartGrid, RestartCache bool StartWithMenu bool Zoomfactor int + DelayedStart bool // if true game, we wait. like pause but program induced // for internal profiling ProfileFile string @@ -38,25 +38,27 @@ type Config struct { } const ( - VERSION = "v0.0.7" + VERSION = "v0.0.8" Alive = 1 Dead = 0 - DEFAULT_WIDTH = 600 - DEFAULT_HEIGHT = 400 - DEFAULT_CELLSIZE = 4 - DEFAULT_ZOOMFACTOR = 150 // FIXME, doesn't work? - DEFAULT_GEOM = "640x384" + DEFAULT_GRID_WIDTH = 600 + DEFAULT_GRID_HEIGHT = 400 + DEFAULT_CELLSIZE = 4 + DEFAULT_ZOOMFACTOR = 150 + DEFAULT_GEOM = "640x384" ) // parse given window geometry and adjust game settings according to it func (config *Config) ParseGeom(geom string) error { - if geom == "" { - config.ScreenWidth = config.Cellsize * config.Width - config.ScreenHeight = config.Cellsize * config.Height - config.Zoomfactor = 0 - return nil - } + // if geom == "" { + // // config.ScreenWidth = config.Cellsize * config.Width + // // config.ScreenHeight = config.Cellsize * config.Height + // config.ScreenWidth = DEFAULT_WIDTH + // config.ScreenHeight = DEFAULT_HEIGHT + // config.Zoomfactor = 0 + // return nil + // } // force a geom geometry := strings.Split(geom, "x") @@ -80,19 +82,15 @@ func (config *Config) ParseGeom(geom string) error { config.ScreenWidth = width - (width % config.Width) config.ScreenHeight = height - (height % config.Height) - if config.ScreenWidth == 0 || config.ScreenHeight == 0 { - return errors.New("the number of requested cells don't fit into the requested window size") - } + */ config.ScreenWidth = width config.ScreenHeight = height - //config.Cellsize = config.ScreenWidth / config.Width config.Cellsize = DEFAULT_CELLSIZE config.Zoomfactor = DEFAULT_ZOOMFACTOR - repr.Println(config) return nil } @@ -121,6 +119,9 @@ func (config *Config) ParseRLE(rlefile string) error { config.Cellsize = config.ScreenWidth / config.Width } + fmt.Printf("width: %d, screenwidth: %d, rlewidth: %d, cellsize: %d\n", + config.Width, config.ScreenWidth, config.RLE.Width, config.Cellsize) + // RLE needs an empty grid config.Empty = true @@ -133,7 +134,7 @@ func (config *Config) ParseRLE(rlefile string) error { } // parse a state file, if given, and adjust game settings accordingly -func (config *Config) ParseStatefile(statefile string) error { +func (config *Config) ParseStatefile() error { if config.Statefile == "" { return nil } @@ -175,8 +176,8 @@ func ParseCommandline() (*Config, error) { ) // commandline params, most configure directly config flags - pflag.IntVarP(&config.Width, "width", "W", DEFAULT_WIDTH, "grid width in cells") - pflag.IntVarP(&config.Height, "height", "H", DEFAULT_HEIGHT, "grid height in cells") + pflag.IntVarP(&config.Width, "width", "W", DEFAULT_GRID_WIDTH, "grid width in cells") + pflag.IntVarP(&config.Height, "height", "H", DEFAULT_GRID_HEIGHT, "grid height in cells") pflag.IntVarP(&config.Cellsize, "cellsize", "c", 8, "cell size in pixels") pflag.StringVarP(&geom, "geom", "G", DEFAULT_GEOM, "window geometry in WxH in pixels, overturns -c") @@ -214,12 +215,18 @@ func ParseCommandline() (*Config, error) { return nil, err } + err = config.ParseStatefile() + if err != nil { + return nil, err + } + // load rule from commandline when no rule came from RLE file, // default is B3/S23, aka conways game of life if config.Rule == nil { config.Rule = ParseGameRule(rule) } + //repr.Println(config) return &config, nil } diff --git a/game.go b/game.go index bf601cf..30e032d 100644 --- a/game.go +++ b/game.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/hajimehoshi/ebiten/v2" ) @@ -53,26 +51,29 @@ func (game *Game) Update() error { scene := game.GetCurrentScene() scene.Update() - fmt.Printf("Clear Screen: %t\n", ebiten.IsScreenClearedEveryFrame()) + next := scene.GetNext() + if next != game.CurrentScene { + scene.ResetNext() + game.CurrentScene = next + } return nil } func (game *Game) Draw(screen *ebiten.Image) { - var nextscene Scene + // first draw primary scene[s], although there are only 1 + for current, scene := range game.Scenes { + if scene.IsPrimary() { + // primary scenes always draw + scene.Draw(screen) + + if current == game.CurrentScene { + // avoid to redraw it in the next step + return + } + } + } + scene := game.GetCurrentScene() - - next := scene.GetNext() - if next != game.CurrentScene { - scene.ResetNext() - game.CurrentScene = next - nextscene = game.GetCurrentScene() - ebiten.SetScreenClearedEveryFrame(nextscene.Clearscreen()) - } - scene.Draw(screen) - - if nextscene != nil { - nextscene.Draw(screen) - } } diff --git a/grid.go b/grid.go index 79f2eca..8201d52 100644 --- a/grid.go +++ b/grid.go @@ -78,6 +78,19 @@ func (grid *Grid) FillRandom() { } } +func (grid *Grid) Dump() { + for y := 0; y < grid.Height; y++ { + for x := 0; x < grid.Width; x++ { + if grid.Data[y][x] == 1 { + fmt.Print("XX") + } else { + fmt.Print(" ") + } + } + fmt.Println() + } +} + // initialize using a given RLE pattern func (grid *Grid) LoadRLE(pattern *rle.RLE) { if pattern != nil { @@ -95,6 +108,8 @@ func (grid *Grid) LoadRLE(pattern *rle.RLE) { } } } + + //grid.Dump() } } diff --git a/main.go b/main.go index 2d86bff..b09a890 100644 --- a/main.go +++ b/main.go @@ -12,11 +12,12 @@ import ( ) func main() { - dau := true + var directstart bool if len(os.Args) > 1 { - dau = false + directstart = true } + config, err := ParseCommandline() if err != nil { log.Fatal(err) @@ -28,8 +29,9 @@ func main() { } start := Play - if dau { + if !directstart { start = Menu + config.DelayedStart = true } game := NewGame(config, SceneName(start)) diff --git a/scene-menu.go b/scene-menu.go index 3beb8fa..6d1c385 100644 --- a/scene-menu.go +++ b/scene-menu.go @@ -46,14 +46,11 @@ func (scene *SceneMenu) SetNext(next SceneName) { scene.Next = next } -func (scene *SceneMenu) Clearscreen() bool { - return false -} - func (scene *SceneMenu) Update() error { scene.Ui.Update() if inpututil.IsKeyJustPressed(ebiten.KeyEscape) || inpututil.IsKeyJustPressed(ebiten.KeyQ) { + scene.Config.DelayedStart = false scene.Leave() } @@ -61,6 +58,10 @@ func (scene *SceneMenu) Update() error { } +func (scene *SceneMenu) IsPrimary() bool { + return false +} + func (scene *SceneMenu) Draw(screen *ebiten.Image) { scene.Ui.Draw(screen) } @@ -102,7 +103,7 @@ func (scene *SceneMenu) Init() { separator2 := NewSeparator() separator3 := NewSeparator() - cancel := NewMenuButton("Close Window", + cancel := NewMenuButton("Back", func(args *widget.ButtonClickedEventArgs) { scene.Leave() }) diff --git a/scene-options.go b/scene-options.go index 5ee1a8b..ab9fe04 100644 --- a/scene-options.go +++ b/scene-options.go @@ -44,7 +44,7 @@ func (scene *SceneOptions) SetNext(next SceneName) { scene.Next = next } -func (scene *SceneOptions) Clearscreen() bool { +func (scene *SceneOptions) IsPrimary() bool { return false } diff --git a/scene-play.go b/scene-play.go index 12c665b..b989cf1 100644 --- a/scene-play.go +++ b/scene-play.go @@ -61,6 +61,10 @@ func NewPlayScene(game *Game, config *Config) Scene { return scene } +func (scene *ScenePlay) IsPrimary() bool { + return true +} + func (scene *ScenePlay) GetNext() SceneName { return scene.Next } @@ -73,10 +77,6 @@ func (scene *ScenePlay) SetNext(next SceneName) { scene.Next = next } -func (scene *ScenePlay) Clearscreen() bool { - return true -} - func (scene *ScenePlay) CheckRule(state int64, neighbors int64) int64 { var nextstate int64 @@ -366,7 +366,8 @@ func (scene *ScenePlay) SaveRectRLE() { func (scene *ScenePlay) Update() error { if scene.Config.Restart { scene.Config.Restart = false - scene.Init() + scene.InitGrid(nil) + scene.InitCache() return nil } @@ -485,9 +486,11 @@ func (scene *ScenePlay) DrawDebug(screen *ebiten.Image) { } debug := fmt.Sprintf( - "FPS: %0.2f, TPG: %d, Mem: %0.2fMB, Gen: %d, Scale: %.02f, Z: %d, Clear: %t %s", + "FPS: %0.2f, TPG: %d, Mem: %0.2fMB, Gen: %d, Scale: %.02f, Z: %d, Cam: %.02f,%.02f %s", ebiten.ActualTPS(), scene.TPG, GetMem(), scene.Generations, - scene.Game.Scale, scene.Camera.ZoomFactor, ebiten.IsScreenClearedEveryFrame(), paused) + scene.Game.Scale, scene.Camera.ZoomFactor, + scene.Camera.Position[0], scene.Camera.Position[1], + paused) FontRenderer.Renderer.SetSizePx(10 + int(scene.Game.Scale*10)) FontRenderer.Renderer.SetTarget(screen) @@ -549,6 +552,7 @@ func (scene *ScenePlay) InitGrid(grid *Grid) { gridb := NewGrid(scene.Config.Width, scene.Config.Height, scene.Config.Density, scene.Config.Empty) history := NewGrid(scene.Config.Width, scene.Config.Height, scene.Config.Density, scene.Config.Empty) + // startup is delayed until user has selected options grida.FillRandom() grida.Copy(history) @@ -607,7 +611,6 @@ func (scene *ScenePlay) Init() { if scene.Config.StateGrid != nil { grid = scene.Config.StateGrid - } scene.Camera = Camera{ @@ -617,12 +620,24 @@ func (scene *ScenePlay) Init() { }, } - scene.World = ebiten.NewImage(scene.Config.ScreenWidth, scene.Config.ScreenHeight) + scene.World = ebiten.NewImage( + scene.Config.Width*scene.Config.Cellsize, + scene.Config.Height*scene.Config.Cellsize, + ) + scene.Cache = ebiten.NewImage(scene.Config.ScreenWidth, scene.Config.ScreenHeight) scene.InitTiles() scene.InitCache() - scene.InitGrid(grid) + + if scene.Config.DelayedStart && !scene.Config.Empty { + scene.Config.Empty = true + scene.InitGrid(grid) + scene.Config.Empty = false + } else { + scene.InitGrid(grid) + } + scene.InitPattern() scene.Index = 0 diff --git a/scene.go b/scene.go index 276931f..0f35bfa 100644 --- a/scene.go +++ b/scene.go @@ -14,9 +14,9 @@ type Scene interface { SetNext(SceneName) GetNext() SceneName ResetNext() - Clearscreen() bool Update() error Draw(screen *ebiten.Image) + IsPrimary() bool // if true, this scene will be always drawn } const ( diff --git a/widgets.go b/widgets.go index 57bfaf2..4c1cbbc 100644 --- a/widgets.go +++ b/widgets.go @@ -69,23 +69,12 @@ func NewSeparator() widget.PreferredSizeLocateableWidget { widget.ContainerOpts.Layout(widget.NewRowLayout( widget.RowLayoutOpts.Direction(widget.DirectionVertical), widget.RowLayoutOpts.Padding(widget.Insets{ - Top: 20, - Bottom: 20, + Top: 3, + Bottom: 0, }))), widget.ContainerOpts.WidgetOpts( widget.WidgetOpts.LayoutData( widget.RowLayoutData{Stretch: true}))) - - c.AddChild(widget.NewGraphic( - widget.GraphicOpts.WidgetOpts(widget.WidgetOpts.LayoutData(widget.RowLayoutData{ - Stretch: true, - MaxHeight: 2, - })), - widget.GraphicOpts.ImageNineSlice( - image.NewNineSliceColor( - color.NRGBA{0xdf, 0xf4, 0xff, 0xff})), - )) - return c } @@ -125,7 +114,7 @@ func NewRowContainer(title string) *RowContainer { ), widget.ContainerOpts.Layout(widget.NewRowLayout( widget.RowLayoutOpts.Direction(widget.DirectionVertical), - widget.RowLayoutOpts.Padding(widget.NewInsetsSimple(20)), + widget.RowLayoutOpts.Padding(widget.NewInsetsSimple(8)), widget.RowLayoutOpts.Spacing(0), )), widget.ContainerOpts.BackgroundImage(buttonImageHover),