package game import ( "fmt" "image" "log" "openquell/assets" "openquell/components" . "openquell/config" "strings" "github.com/hajimehoshi/ebiten/v2" "github.com/mlange-42/arche/ecs" "github.com/mlange-42/arche/filter" ) type Level struct { Grid *Grid Cellsize, Width, Height int World *ecs.World Name string Description string Background *ebiten.Image Mapslice map[image.Point]*assets.Tile } func NewLevel(game *Game, cellsize int, plan *assets.RawLevel) *Level { //grid := NewGrid(game, cellsize, plan) return &Level{ //Grid: grid, Mapslice: LevelToSlice(game, plan, cellsize), Cellsize: cellsize, World: game.World, Width: game.ScreenWidth, Height: game.ScreenHeight, Description: plan.Description, Background: plan.Background, } } func (level *Level) Update() { //playermapper := generic.NewMap3[components.Position, components.Velocity, components.Renderable](level.World) positionid := ecs.ComponentID[components.Position](level.World) velocityid := ecs.ComponentID[components.Velocity](level.World) playerid := ecs.ComponentID[components.Player](level.World) //solidid := ecs.ComponentID[components.Solid](level.World) //renderid := ecs.ComponentID[components.Renderable](level.World) selector := filter.All(positionid, velocityid, playerid) query := level.World.Query(selector) //tileselector := filter.All(positionid, solidid, renderid) //tilequery := level.World.Query(tileselector) for query.Next() { playerposition := (*components.Position)(query.Get(positionid)) velocity := (*components.Velocity)(query.Get(velocityid)) switch { case ebiten.IsKeyPressed(ebiten.KeyRight): velocity.Change(East) case ebiten.IsKeyPressed(ebiten.KeyLeft): velocity.Change(West) case ebiten.IsKeyPressed(ebiten.KeyDown): velocity.Change(South) case ebiten.IsKeyPressed(ebiten.KeyUp): velocity.Change(North) // other keys: : switch player, etc } /* // Use this to check against obstacles, collectibles etc for tilequery.Next() { tilepos := (*components.Position)(tilequery.Get(positionid)) if velocity.Moving() { intersects, newpos := tilepos.Intersects(playerposition, velocity) if intersects { fmt.Printf("collision detected. tile: %s\n", tilepos) fmt.Printf(" player: %s\n", playerposition) fmt.Printf(" new: %s\n", newpos) playerposition.Set(newpos) fmt.Printf(" player new: %s\n", playerposition) velocity.Change(Stop) } } } */ if velocity.Moving() { ok, tilepos := level.Grid.GetSolidNeighborPosition(playerposition, velocity, true) if ok { intersects, newpos := tilepos.Intersects(playerposition, velocity) if intersects { fmt.Printf("collision detected. tile: %s\n", tilepos) fmt.Printf(" player: %s\n", playerposition) fmt.Printf(" new: %s\n", newpos) playerposition.Set(newpos) fmt.Printf(" player new: %s\n", playerposition) velocity.Change(Stop) } } } playerposition.Move(velocity) } } func (level *Level) Position2Point(position *components.Position) image.Point { return image.Point{ int(position.X) / level.Cellsize, int(position.Y) / level.Cellsize, } } // return the tile the moving object would end up on if indeed moving func (level *Level) GetTile(position *components.Position, velocity *components.Velocity) *assets.Tile { newpoint := image.Point{ int(position.X+velocity.Data.X) / level.Cellsize, int(position.Y+velocity.Data.Y) / level.Cellsize, } tile := level.Mapslice[newpoint] return tile } func (level *Level) Draw(screen *ebiten.Image) { // FIXME: move out op := &ebiten.DrawImageOptions{} screen.DrawImage(level.Background, op) rid := ecs.ComponentID[components.Renderable](level.World) pid := ecs.ComponentID[components.Position](level.World) selector := filter.All(rid, pid) query := level.World.Query(selector) for query.Next() { pos := (*components.Position)(query.Get(pid)) sprite := (*components.Renderable)(query.Get(rid)) op := &ebiten.DrawImageOptions{} op.GeoM.Translate(float64(pos.X), float64(pos.Y)) screen.DrawImage(sprite.Image, op) } } func (level *Level) SetupGrid(game *Game) { level.Grid = NewGrid(game, level.Cellsize, level.Mapslice) } func LevelToSlice(game *Game, level *assets.RawLevel, tilesize int) map[image.Point]*assets.Tile { size := game.ScreenWidth * game.ScreenHeight mapslice := make(map[image.Point]*assets.Tile, size) for y, line := range strings.Split(string(level.Data), "\n") { if len(line) != game.ScreenWidth/tilesize && y < game.ScreenHeight/tilesize { log.Fatalf("line %d doesn't contain %d tiles, but %d", y, game.ScreenWidth/tilesize, len(line)) } for x, char := range line { mapslice[image.Point{x, y}] = assets.Tiles[byte(char)] } } return mapslice }