added sphere bounce over the map borders

This commit is contained in:
Thomas von Dein 2024-02-06 19:02:25 +01:00
parent 014209898f
commit c9a57142e7
10 changed files with 130 additions and 73 deletions

View File

@ -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

View File

@ -2,16 +2,16 @@ Description: find the fruit
Background: background-orange
##############
# #
############ #
# S #
# ############
# #
############ #
# # # #
# ##### # # #
# S #
# ######## ###
#
############ #
# # #
##############
# # ######## #
# #
# ############

View File

@ -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 {

View File

@ -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
}

View File

@ -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
}

View File

@ -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,6 +81,11 @@ func (level *Level) Update() {
*/
if velocity.Moving() {
ok, newpos := level.Grid.BumpEdge(playerposition, velocity)
if ok {
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)
@ -104,6 +100,7 @@ func (level *Level) Update() {
}
}
}
}
playerposition.Move(velocity)
}

49
game/levelscene.go Normal file
View File

@ -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)
}

View File

@ -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)
}

View File

@ -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 {

BIN
openquell

Binary file not shown.