package game import ( "fmt" "image" "log" "openquell/assets" "openquell/components" . "openquell/config" "github.com/alecthomas/repr" "github.com/mlange-42/arche/generic" ) type Grid struct { Width int Height int Size int Tilesize int TilesX int TilesY 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(game *Game, tilesize 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.NewMap4[ components.Position, components.Velocity, components.Renderable, components.Player](game.World) solidmapper := generic.NewMap4[ components.Position, components.Renderable, components.Tilish, components.Solid](game.World) emptymapper := generic.NewMap2[components.Position, components.Tilish](game.World) colmapper := generic.NewMap3[ components.Position, components.Renderable, components.Collectible](game.World) var pos *components.Position var render *components.Renderable 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, _ = playermapper.Get(entity) fmt.Printf("player start pos: %d,%d\n", point.X*tilesize, point.Y*tilesize) 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: game.ScreenWidth, Height: game.ScreenHeight, TilesX: game.ScreenWidth / tilesize, TilesY: game.ScreenHeight / tilesize, Map: mapslice, } } func (grid *Grid) GetSolidNeighborPosition( position *components.Position, velocity *components.Velocity, solid bool) (bool, *components.Position) { if !solid { return false, nil } // set to true, ifwe are already on the last tile in the current // direction, i.e. on the edge of the grid edge := true neighborpos := position.Point() switch velocity.Direction { case East: if neighborpos.X < grid.TilesX { neighborpos.X++ edge = false } case West: if neighborpos.X > 0 { neighborpos.X-- edge = false } case South: if neighborpos.Y < grid.TilesY { neighborpos.Y++ edge = false } case North: if neighborpos.Y > 0 { neighborpos.Y-- edge = false } } newpos := components.NewPosition(neighborpos, grid.Tilesize) repr.Println(newpos) if !edge && grid.Map[neighborpos].Solid { return true, newpos } return false, nil } func (grid *Grid) BumpEdge( pos *components.Position, velocity *components.Velocity) (bool, *components.Position) { x := pos.X + velocity.Data.X y := pos.Y + velocity.Data.Y if x < 0 || x > grid.Width-grid.Tilesize || y < 0 || y > grid.Height-grid.Tilesize { newpos := &components.Position{} X := pos.X Y := pos.Y switch velocity.Direction { case East: X = 0 fmt.Println("east X=0") case West: X = grid.Width - grid.Tilesize fmt.Println("west X=max") case South: Y = 0 fmt.Println("south y=0") case North: Y = grid.Height - grid.Tilesize fmt.Println("north y=max") } newpos.Update(X, Y, grid.Tilesize) return true, newpos } return false, nil }