added player loop detection, loose level if last player loops
This commit is contained in:
parent
5d2475d525
commit
707281212a
14
TODO.md
14
TODO.md
@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
- ignore comments in lvl files
|
- ignore comments 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
|
|
||||||
|
|
||||||
- Start the game end timer and add a score FIXME: put the actual max
|
- Start the game end timer and add a score FIXME: put the actual max
|
||||||
reachable score into the level definition along with the minimum
|
reachable score into the level definition along with the minimum
|
||||||
steps required to reach it, also add a step counter
|
steps required to reach it, also add a step counter
|
||||||
@ -15,19 +12,8 @@
|
|||||||
- Add some final message when the player reaches the last level, start
|
- Add some final message when the player reaches the last level, start
|
||||||
from scratch or a message to buy me some beer, whatever
|
from scratch or a message to buy me some beer, whatever
|
||||||
|
|
||||||
- Check player-player collisions!
|
|
||||||
|
|
||||||
- Add player mergers, possibly as an option, so maybe we could have
|
|
||||||
different primary and secondary players: one pair can merge, the
|
|
||||||
other not. Like S + s and M + m or something.
|
|
||||||
|
|
||||||
- Add shaders for animation (player destruction etc)
|
- Add shaders for animation (player destruction etc)
|
||||||
|
|
||||||
- Add player HUD + Stats (as hud_system!)
|
|
||||||
|
|
||||||
- Entity Observers don't work, removed entities remain there, errors
|
|
||||||
about dead entities, had to add Alive checks, and in obstacle_system
|
|
||||||
even remove the player manually from the world.
|
|
||||||
|
|
||||||
|
|
||||||
## Collider Rework
|
## Collider Rework
|
||||||
|
|||||||
@ -4,14 +4,14 @@ Background: background-lila
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
W
|
||||||
|
|
||||||
|
|
||||||
S
|
S # o
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
|
o
|
||||||
|
#
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,9 @@ import "github.com/hajimehoshi/ebiten/v2"
|
|||||||
type Player struct {
|
type Player struct {
|
||||||
IsPrimary bool
|
IsPrimary bool
|
||||||
Sprites []*ebiten.Image
|
Sprites []*ebiten.Image
|
||||||
|
LoopPos *Position
|
||||||
|
LoopStart bool
|
||||||
|
LoopCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *Player) SwitchSprite() *ebiten.Image {
|
func (player *Player) SwitchSprite() *ebiten.Image {
|
||||||
|
|||||||
@ -44,7 +44,7 @@ func NewLevel(game *Game, cellsize int, plan *assets.RawLevel) *Level {
|
|||||||
systemlist = append(systemlist, systems.NewObstacleSystem(game.World, gridcontainer))
|
systemlist = append(systemlist, systems.NewObstacleSystem(game.World, gridcontainer))
|
||||||
|
|
||||||
systemlist = append(systemlist,
|
systemlist = append(systemlist,
|
||||||
systems.NewPlayerSystem(game.World, gridcontainer))
|
systems.NewPlayerSystem(game.World, gridcontainer, game.ScreenWidth, game.ScreenHeight))
|
||||||
|
|
||||||
systemlist = append(systemlist, systems.NewParticleSystem(game.World, game.Cellsize))
|
systemlist = append(systemlist, systems.NewParticleSystem(game.World, game.Cellsize))
|
||||||
|
|
||||||
|
|||||||
@ -90,6 +90,7 @@ func NewGrid(world *ecs.World,
|
|||||||
vel.Speed = config.PLAYERSPEED
|
vel.Speed = config.PLAYERSPEED
|
||||||
player.IsPrimary = tile.IsPrimary
|
player.IsPrimary = tile.IsPrimary
|
||||||
player.Sprites = tile.Tiles
|
player.Sprites = tile.Tiles
|
||||||
|
player.LoopPos = &components.Position{Cellsize: tilesize}
|
||||||
case tile.Collectible:
|
case tile.Collectible:
|
||||||
entity := colmapper.New()
|
entity := colmapper.New()
|
||||||
pos, render, _ = colmapper.Get(entity)
|
pos, render, _ = colmapper.Get(entity)
|
||||||
|
|||||||
@ -18,13 +18,16 @@ type PlayerSystem struct {
|
|||||||
World *ecs.World
|
World *ecs.World
|
||||||
Selector *generic.Filter4[Position, Velocity, Player, Renderable]
|
Selector *generic.Filter4[Position, Velocity, Player, Renderable]
|
||||||
GridContainer *grid.GridContainer
|
GridContainer *grid.GridContainer
|
||||||
|
Width, Height int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPlayerSystem(world *ecs.World, gridcontainer *grid.GridContainer) System {
|
func NewPlayerSystem(world *ecs.World, gridcontainer *grid.GridContainer, width, height int) System {
|
||||||
system := &PlayerSystem{
|
system := &PlayerSystem{
|
||||||
Selector: generic.NewFilter4[Position, Velocity, Player, Renderable](),
|
Selector: generic.NewFilter4[Position, Velocity, Player, Renderable](),
|
||||||
GridContainer: gridcontainer,
|
GridContainer: gridcontainer,
|
||||||
World: world,
|
World: world,
|
||||||
|
Width: width,
|
||||||
|
Height: height,
|
||||||
}
|
}
|
||||||
|
|
||||||
return system
|
return system
|
||||||
@ -48,7 +51,7 @@ func (system PlayerSystem) Update() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if the user alters or initiates movement
|
// check if the user alters or initiates movement
|
||||||
system.CheckMovement(velocity)
|
system.CheckMovement(playerposition, velocity, player)
|
||||||
|
|
||||||
// check if player collides with walls or edges
|
// check if player collides with walls or edges
|
||||||
system.CheckGridCollision(playerposition, velocity)
|
system.CheckGridCollision(playerposition, velocity)
|
||||||
@ -56,6 +59,15 @@ func (system PlayerSystem) Update() error {
|
|||||||
if count > 1 {
|
if count > 1 {
|
||||||
// check if player collides with another player, fuse them if any
|
// check if player collides with another player, fuse them if any
|
||||||
EntitiesToRemove = system.CheckPlayerCollision(playerposition, velocity, query.Entity())
|
EntitiesToRemove = system.CheckPlayerCollision(playerposition, velocity, query.Entity())
|
||||||
|
} else {
|
||||||
|
// only 1 player left or one is max
|
||||||
|
EntitiesToRemove = system.CheckPlayerLooping(
|
||||||
|
playerposition, velocity, player, query.Entity())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !velocity.Moving() {
|
||||||
|
// disable loop detection
|
||||||
|
player.LoopCount = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,17 +142,33 @@ func (system *PlayerSystem) SwitchPlayers() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (system *PlayerSystem) CheckMovement(velocity *components.Velocity) {
|
func (system *PlayerSystem) CheckMovement(
|
||||||
|
position *components.Position,
|
||||||
|
velocity *components.Velocity,
|
||||||
|
player *components.Player) {
|
||||||
|
|
||||||
|
moved := false
|
||||||
|
|
||||||
if !velocity.Moving() {
|
if !velocity.Moving() {
|
||||||
switch {
|
switch {
|
||||||
case ebiten.IsKeyPressed(ebiten.KeyRight):
|
case ebiten.IsKeyPressed(ebiten.KeyRight):
|
||||||
velocity.Change(East)
|
velocity.Change(East)
|
||||||
|
moved = true
|
||||||
case ebiten.IsKeyPressed(ebiten.KeyLeft):
|
case ebiten.IsKeyPressed(ebiten.KeyLeft):
|
||||||
velocity.Change(West)
|
velocity.Change(West)
|
||||||
|
moved = true
|
||||||
case ebiten.IsKeyPressed(ebiten.KeyDown):
|
case ebiten.IsKeyPressed(ebiten.KeyDown):
|
||||||
velocity.Change(South)
|
velocity.Change(South)
|
||||||
|
moved = true
|
||||||
case ebiten.IsKeyPressed(ebiten.KeyUp):
|
case ebiten.IsKeyPressed(ebiten.KeyUp):
|
||||||
velocity.Change(North)
|
velocity.Change(North)
|
||||||
|
moved = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if moved {
|
||||||
|
// will be reset every time the user initiates player movement
|
||||||
|
player.LoopPos.Set(position)
|
||||||
|
player.LoopCount = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,9 +189,6 @@ func (system *PlayerSystem) CheckGridCollision(
|
|||||||
tilepos.Point(), "playerpos", playerposition)
|
tilepos.Point(), "playerpos", playerposition)
|
||||||
intersects, newpos := tilepos.Intersects(playerposition, velocity)
|
intersects, newpos := tilepos.Intersects(playerposition, velocity)
|
||||||
if intersects {
|
if intersects {
|
||||||
// slog.Debug("collision detected", "tile",
|
|
||||||
// tilepos, "player", playerposition, "new", newpos)
|
|
||||||
|
|
||||||
playerposition.Set(newpos)
|
playerposition.Set(newpos)
|
||||||
velocity.Change(Stop)
|
velocity.Change(Stop)
|
||||||
}
|
}
|
||||||
@ -202,3 +227,39 @@ func (system *PlayerSystem) CheckPlayerCollision(
|
|||||||
// FIXME: add an animation highlighting the fusion
|
// FIXME: add an animation highlighting the fusion
|
||||||
return EntitiesToRemove
|
return EntitiesToRemove
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (system *PlayerSystem) CheckPlayerLooping(
|
||||||
|
position *components.Position,
|
||||||
|
velocity *components.Velocity,
|
||||||
|
player *components.Player,
|
||||||
|
entity ecs.Entity) []ecs.Entity {
|
||||||
|
|
||||||
|
if player.LoopPos.Rect == nil {
|
||||||
|
// hasn't moved
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
EntitiesToRemove := []ecs.Entity{}
|
||||||
|
|
||||||
|
ok, _ := player.LoopPos.Intersects(position, velocity)
|
||||||
|
if ok {
|
||||||
|
// Fatal: loop detected with last player
|
||||||
|
player.LoopStart = true
|
||||||
|
} else {
|
||||||
|
// no intersection with old pos anymore
|
||||||
|
if player.LoopStart {
|
||||||
|
// loop detection active
|
||||||
|
player.LoopCount++
|
||||||
|
max := system.Width
|
||||||
|
if velocity.Direction == North || velocity.Direction == South {
|
||||||
|
max = system.Height
|
||||||
|
}
|
||||||
|
|
||||||
|
// we haved moved one time around the whole screen, loose
|
||||||
|
if (player.LoopCount * velocity.Speed) > max {
|
||||||
|
EntitiesToRemove = append(EntitiesToRemove, entity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EntitiesToRemove
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user