package systems import ( "openquell/assets" "openquell/components" . "openquell/components" "openquell/config" "openquell/util" "log" "github.com/hajimehoshi/ebiten/v2" "github.com/mlange-42/arche/ecs" "github.com/mlange-42/arche/generic" ) type GridSystem struct { World *ecs.World Selector *generic.Filter3[Renderable, Position, Solid] UseCache bool Cache *ebiten.Image Count int // register tile count, invalidates cache Background *ebiten.Image Animate components.Animation BackgroundAnimated bool Width, Height, Tilesize int } func NewGridSystem(world *ecs.World, width, height, tilesize int, background string) System { cache := ebiten.NewImage(width, height) if !util.Exists(assets.Assets, background) { log.Fatalf("no background %s in assets", background) } system := &GridSystem{ Selector: generic.NewFilter3[Renderable, Position, Solid](), UseCache: false, Cache: cache, Width: width, Height: height, Tilesize: tilesize, Background: assets.Assets[background], World: world, } if util.Exists(assets.Animations, background+"-animated") { system.BackgroundAnimated = true system.Animate = components.Animation{ Active: true, Loop: true, Sprites: assets.Animations[background+"-animated"].Sprites, } system.Animate.Timer.Start(config.ANIMATION_LOOPWAIT) } return system } func (system *GridSystem) Update() error { if system.BackgroundAnimated { if system.Animate.Timer.IsReady() { switch { // animation shows from earlier tick, animate case system.Animate.Index > -1 && system.Animate.Index < len(system.Animate.Sprites)-1: system.Animate.Index += 1 system.Animate.Timer.Start(system.Animate.GetDuration()) default: // last sprite reached if system.Animate.Loop { system.Animate.Index = 0 } } } else { system.Animate.Timer.Update() } } return nil } func (system *GridSystem) Draw(screen *ebiten.Image) { op := &ebiten.DrawImageOptions{} query := system.Selector.Query(system.World) if !system.UseCache || query.Count() != system.Count || system.BackgroundAnimated { // map not cached or cacheable, write it to the cache if system.BackgroundAnimated { system.Cache.DrawImage(system.Animate.GetSprite(), op) } else { system.Cache.DrawImage(system.Background, op) } system.Count = query.Count() counter := 0 for query.Next() { sprite, pos, _ := query.Get() counter++ op.GeoM.Reset() op.GeoM.Translate(float64(pos.X), float64(pos.Y)) system.Cache.DrawImage(sprite.Image, op) } op.GeoM.Reset() screen.DrawImage(system.Cache, op) system.UseCache = true } else { // use the cached map op.GeoM.Reset() screen.DrawImage(system.Cache, op) query.Close() } }