diff --git a/TODO.md b/TODO.md index 243c589..9b8cfad 100644 --- a/TODO.md +++ b/TODO.md @@ -7,3 +7,4 @@ - use first line as background image name - ignore comments in lvl files - add whitespace-mode flag in lvl files +- check when sphere bounces from one end to the other endlessly w/o any solids in between. this is a game lock and equals game over diff --git a/assets/levels/gurke.lvl b/assets/levels/gurke.lvl index bd2ad5d..943eb97 100644 --- a/assets/levels/gurke.lvl +++ b/assets/levels/gurke.lvl @@ -2,16 +2,16 @@ Description: find the fruit Background: background-orange - ############## - # # - ############ # - # S # # ############ # # ############ # - # # # # - # ##### # # # - # # # - ############## + # S # + # ######## ### + # + ############ # + # # # + # # ######## # + # # + # ############ diff --git a/components/position.go b/components/position.go index 65a030b..2351e86 100644 --- a/components/position.go +++ b/components/position.go @@ -26,7 +26,7 @@ func (position *Position) Update(x, y int, size ...int) { position.Rect = &rect } -func NewPosition(point *image.Point, cellsize int) *Position { +func NewPosition(point image.Point, cellsize int) *Position { position := &Position{} position.Update(point.X*cellsize, point.Y*cellsize, cellsize) return position @@ -39,8 +39,8 @@ func (position *Position) GetMoved(velosity *Velocity) *Position { return pos } -func (position *Position) Point() *image.Point { - return &image.Point{position.X / position.Cellsize, position.Y / position.Cellsize} +func (position *Position) Point() image.Point { + return image.Point{position.X / position.Cellsize, position.Y / position.Cellsize} } func (position *Position) Left() int { diff --git a/game/game.go b/game/game.go index 8f9094e..ea8e094 100644 --- a/game/game.go +++ b/game/game.go @@ -1,6 +1,7 @@ package game import ( + "fmt" "image" "github.com/hajimehoshi/ebiten/v2" @@ -12,10 +13,10 @@ type Game struct { Bounds image.Rectangle ScreenWidth, ScreenHeight int CurrentLevel int - Scenes []Scene + Scenes map[int]Scene } -func NewGame(width, height, startlevel int) *Game { +func NewGame(width, height, startlevel int, startscene int) *Game { world := ecs.NewWorld() game := &Game{ @@ -24,10 +25,12 @@ func NewGame(width, height, startlevel int) *Game { World: &world, ScreenWidth: width, ScreenHeight: height, + Scenes: map[int]Scene{}, } - levelscene := NewLevelScene(game, startlevel) - game.Scenes = append(game.Scenes, levelscene) + game.Scenes[Play] = NewLevelScene(game, startlevel) + + fmt.Println(game.World.Stats().String()) return game } diff --git a/game/grid.go b/game/grid.go index d195cf5..38ab634 100644 --- a/game/grid.go +++ b/game/grid.go @@ -8,6 +8,7 @@ import ( "openquell/components" . "openquell/config" + "github.com/alecthomas/repr" "github.com/mlange-42/arche/generic" ) @@ -90,7 +91,6 @@ func (grid *Grid) GetSolidNeighborPosition( return false, nil } - fmt.Println(position) // set to true, ifwe are already on the last tile in the current // direction, i.e. on the edge of the grid edge := true @@ -120,9 +120,43 @@ func (grid *Grid) GetSolidNeighborPosition( } newpos := components.NewPosition(neighborpos, grid.Tilesize) - fmt.Println(newpos, edge) + repr.Println(newpos) - if !edge && grid.Map[*neighborpos].Solid { + 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 } diff --git a/game/levels.go b/game/levels.go index bdb351f..2f682f7 100644 --- a/game/levels.go +++ b/game/levels.go @@ -25,10 +25,7 @@ type Level struct { } 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, @@ -40,19 +37,13 @@ func NewLevel(game *Game, cellsize int, plan *assets.RawLevel) *Level { } 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)) @@ -90,17 +81,23 @@ func (level *Level) Update() { */ if velocity.Moving() { - ok, tilepos := level.Grid.GetSolidNeighborPosition(playerposition, velocity, true) + ok, newpos := level.Grid.BumpEdge(playerposition, velocity) 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) + fmt.Printf("falling off the edge, new pos: %v\n", newpos) + playerposition.Set(newpos) + } else { + 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.Set(newpos) + fmt.Printf(" player new: %s\n", playerposition) + velocity.Change(Stop) + } } } } diff --git a/game/levelscene.go b/game/levelscene.go new file mode 100644 index 0000000..0aa9e73 --- /dev/null +++ b/game/levelscene.go @@ -0,0 +1,49 @@ +package game + +import ( + "openquell/assets" + + "github.com/hajimehoshi/ebiten/v2" +) + +type LevelScene struct { + CurrentLevel int + Levels []*Level + Next int + Whoami int +} + +// Implements the actual playing Scene +func NewLevelScene(game *Game, startlevel int) Scene { + scene := &LevelScene{CurrentLevel: startlevel, Whoami: Play} + + scene.GenerateLevels(game) + scene.Levels[game.CurrentLevel].SetupGrid(game) + + return scene +} + +func (scene *LevelScene) GenerateLevels(game *Game) { + for _, level := range assets.Levels { + scene.Levels = append(scene.Levels, NewLevel(game, 32, &level)) + } +} + +// Interface methods +func (scene *LevelScene) SetNext() int { + if scene.Whoami != scene.Next { + return scene.Next + } + + return 0 +} + +func (scene *LevelScene) Update() error { + scene.Levels[scene.CurrentLevel].Update() + return nil +} + +func (scene *LevelScene) Draw(screen *ebiten.Image) { + screen.Clear() + scene.Levels[scene.CurrentLevel].Draw(screen) +} diff --git a/game/scene.go b/game/scene.go index 11a2c86..fdc7c50 100644 --- a/game/scene.go +++ b/game/scene.go @@ -1,51 +1,24 @@ package game import ( - "fmt" - "openquell/assets" - "github.com/hajimehoshi/ebiten/v2" ) +const ( + Welcome = iota + Select + Play + About + Settings +) + // Wrapper for different screens to be shown, as Welcome, Options, // About, Select Level and of course the actual Levels. // Scenes are responsible for screen clearing! That way a scene is able // to render its content onto the running level, e.g. the options scene // etc. type Scene interface { + SetNext() int Update() error Draw(screen *ebiten.Image) } - -type LevelScene struct { - Game *Game - CurrentLevel int - Levels []*Level -} - -// Implements the actual playing Scene -func NewLevelScene(game *Game, startlevel int) Scene { - scene := &LevelScene{Game: game, CurrentLevel: startlevel} - - scene.GenerateLevels() - scene.Levels[game.CurrentLevel].SetupGrid(game) - fmt.Println(game.World.Stats().String()) - - return scene -} - -func (scene *LevelScene) GenerateLevels() { - for _, level := range assets.Levels { - scene.Levels = append(scene.Levels, NewLevel(scene.Game, 32, &level)) - } -} - -func (scene *LevelScene) Update() error { - scene.Levels[scene.CurrentLevel].Update() - return nil -} - -func (scene *LevelScene) Draw(screen *ebiten.Image) { - screen.Clear() - scene.Levels[scene.CurrentLevel].Draw(screen) -} diff --git a/main.go b/main.go index 1ae13f7..fe266ce 100644 --- a/main.go +++ b/main.go @@ -16,7 +16,7 @@ func main() { ebiten.SetWindowSize(width, height) ebiten.SetWindowTitle("openquell") - g := game.NewGame(width, height, 0) + g := game.NewGame(width, height, 0, game.Play) err := ebiten.RunGame(g) if err != nil { diff --git a/openquell b/openquell index 29df0e5..7d11b44 100755 Binary files a/openquell and b/openquell differ