package grid import ( "image" "log" "log/slog" "openquell/assets" "openquell/components" "openquell/config" "openquell/observers" "github.com/mlange-42/arche/ecs" "github.com/mlange-42/arche/generic" ) type Grid struct { Width int Height int Size int Tilesize int Map map[image.Point]*assets.Tile } // FIXME: put component addition into extra callable function, to be called // by game.go in a level-loop. Also remove components of previous level func NewGrid(world *ecs.World, tilesize, width, height int, mapslice map[image.Point]*assets.Tile) *Grid { // we use this to turn our tiles into iterable entities, used for // collision detection, transformation and other things playermapper := generic.NewMap5[ components.Position, components.Velocity, components.Renderable, components.Speed, components.Player](world) solidmapper := generic.NewMap4[ components.Position, components.Renderable, components.Tilish, components.Solid](world) emptymapper := generic.NewMap2[components.Position, components.Tilish](world) colmapper := generic.NewMap3[ components.Position, components.Renderable, components.Collectible](world) var pos *components.Position var render *components.Renderable var speed *components.Speed playerobserver := observers.GetPlayerObserver(world) for point, tile := range mapslice { switch tile.Renderable { case true: switch { case tile.Solid: entity := solidmapper.New() pos, render, _, _ = solidmapper.Get(entity) case tile.Player: entity := playermapper.New() pos, _, render, speed, _ = playermapper.Get(entity) playerobserver.AddEntity(entity) speed.Value = config.PLAYERSPEED slog.Debug("player start pos", "X", point.X*tilesize, "Y", point.Y*tilesize, "Z", 191) case tile.Collectible: entity := colmapper.New() pos, render, _ = colmapper.Get(entity) default: log.Fatalln("unsupported tile type encountered") } render.Image = tile.Sprite default: // empty cell, this is where the player[s] move. No // sprite required since every level has a background // image. entity := emptymapper.New() pos, _ = emptymapper.Get(entity) } // however, every tile has a position pos.Update(point.X*tilesize, point.Y*tilesize, tilesize) } return &Grid{ Size: len(mapslice), Tilesize: tilesize, Width: width, Height: height, Map: mapslice, } } // return the tile the moving object would end up on if indeed moving func (grid *Grid) GetTile( position *components.Position, velocity *components.Velocity) *assets.Tile { newpoint := image.Point{ int(position.X+velocity.Data.X) / grid.Tilesize, int(position.Y+velocity.Data.Y) / grid.Tilesize, } tile := grid.Map[newpoint] return tile }