From 5d2475d525429d2c5110a49704036e3cc0381cc2 Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Tue, 27 Feb 2024 17:28:18 +0100 Subject: [PATCH] two players fuse now if they collide --- systems/player_system.go | 192 ++++++++++++++++++++++++--------------- 1 file changed, 120 insertions(+), 72 deletions(-) diff --git a/systems/player_system.go b/systems/player_system.go index 979aa6b..a5f03d3 100644 --- a/systems/player_system.go +++ b/systems/player_system.go @@ -2,9 +2,11 @@ package systems import ( "log/slog" + "openquell/components" . "openquell/components" . "openquell/config" "openquell/grid" + "openquell/observers" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/inpututil" @@ -29,6 +31,67 @@ func NewPlayerSystem(world *ecs.World, gridcontainer *grid.GridContainer) System } func (system PlayerSystem) Update() error { + var EntitiesToRemove []ecs.Entity + + // check if we need to switch player[s] + system.SwitchPlayers() + + // check player movements etc + query := system.Selector.Query(system.World) + count := query.Count() + + for query.Next() { + playerposition, velocity, player, _ := query.Get() + + if !player.IsPrimary { + continue + } + + // check if the user alters or initiates movement + system.CheckMovement(velocity) + + // check if player collides with walls or edges + system.CheckGridCollision(playerposition, velocity) + + if count > 1 { + // check if player collides with another player, fuse them if any + EntitiesToRemove = system.CheckPlayerCollision(playerposition, velocity, query.Entity()) + } + } + + // 2nd pass: move player after obstacle or collectible updates + query = system.Selector.Query(system.World) + for query.Next() { + playerposition, velocity, _, _ := query.Get() + playerposition.Move(velocity) + } + + // we may have lost players, remove them here + + for _, entity := range EntitiesToRemove { + slog.Debug("remove player", "ent", entity.IsZero()) + system.World.RemoveEntity(entity) + } + + return nil +} + +func (system *PlayerSystem) Draw(screen *ebiten.Image) { + // write the movable tiles + op := &ebiten.DrawImageOptions{} + query := system.Selector.Query(system.World) + + for query.Next() { + pos, _, _, sprite := query.Get() + + op.GeoM.Reset() + op.GeoM.Translate(float64(pos.X), float64(pos.Y)) + + screen.DrawImage(sprite.Image, op) + } +} + +func (system *PlayerSystem) SwitchPlayers() { // first check if we need to switch player switchable := false query := system.Selector.Query(system.World) @@ -65,92 +128,77 @@ func (system PlayerSystem) Update() error { } } } +} - // check player movements etc - query = system.Selector.Query(system.World) - for query.Next() { - playerposition, velocity, player, _ := query.Get() - - if !player.IsPrimary { - continue +func (system *PlayerSystem) CheckMovement(velocity *components.Velocity) { + if !velocity.Moving() { + 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) } + } +} - if !velocity.Moving() { - 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) - case ebiten.IsKeyPressed(ebiten.Key1): - velocity.Speed = 1 - case ebiten.IsKeyPressed(ebiten.Key2): - velocity.Speed = 2 - case ebiten.IsKeyPressed(ebiten.Key3): - velocity.Speed = 3 - case ebiten.IsKeyPressed(ebiten.Key4): - velocity.Speed = 4 - case ebiten.IsKeyPressed(ebiten.Key5): - velocity.Speed = 5 - case ebiten.IsKeyPressed(ebiten.Key6): - velocity.Speed = 6 - case ebiten.IsKeyPressed(ebiten.Key7): - velocity.Speed = 7 - case ebiten.IsKeyPressed(ebiten.Key8): - velocity.Speed = 8 - case ebiten.IsKeyPressed(ebiten.Key9): - velocity.Speed = 9 - // other keys: : switch player, etc - } - } +func (system *PlayerSystem) CheckGridCollision( + playerposition *components.Position, + velocity *components.Velocity) { - if velocity.Moving() { - ok, newpos := system.GridContainer.Grid.BumpEdge(playerposition, velocity) + if velocity.Moving() { + ok, newpos := system.GridContainer.Grid.BumpEdge(playerposition, velocity) + if ok { + //slog.Debug("falling off the edge", "newpos", newpos) + playerposition.Set(newpos) + } else { + ok, tilepos := system.GridContainer.Grid.GetSolidNeighborPosition(playerposition, velocity, true) if ok { - //slog.Debug("falling off the edge", "newpos", newpos) - playerposition.Set(newpos) - } else { - ok, tilepos := system.GridContainer.Grid.GetSolidNeighborPosition(playerposition, velocity, true) - if ok { - slog.Debug("HaveSolidNeighbor", "ok", ok, "tilepos", - tilepos.Point(), "playerpos", playerposition) - intersects, newpos := tilepos.Intersects(playerposition, velocity) - if intersects { - // slog.Debug("collision detected", "tile", - // tilepos, "player", playerposition, "new", newpos) + slog.Debug("HaveSolidNeighbor", "ok", ok, "tilepos", + tilepos.Point(), "playerpos", playerposition) + intersects, newpos := tilepos.Intersects(playerposition, velocity) + if intersects { + // slog.Debug("collision detected", "tile", + // tilepos, "player", playerposition, "new", newpos) - playerposition.Set(newpos) - velocity.Change(Stop) - } + playerposition.Set(newpos) + velocity.Change(Stop) } } } } - - query = system.Selector.Query(system.World) - for query.Next() { - // move player after obstacle or collectible updates - playerposition, velocity, _, _ := query.Get() - playerposition.Move(velocity) - } - - return nil } -func (system *PlayerSystem) Draw(screen *ebiten.Image) { - // write the movable tiles - op := &ebiten.DrawImageOptions{} - query := system.Selector.Query(system.World) +func (system *PlayerSystem) CheckPlayerCollision( + position *components.Position, + velocity *components.Velocity, + player ecs.Entity) []ecs.Entity { - for query.Next() { - pos, _, _, sprite := query.Get() + observer := observers.GetGameObserver(system.World) + posID := ecs.ComponentID[components.Position](system.World) + EntitiesToRemove := []ecs.Entity{} - op.GeoM.Reset() - op.GeoM.Translate(float64(pos.X), float64(pos.Y)) + for _, otherplayer := range observer.GetPlayers() { + if !system.World.Alive(otherplayer) { + continue + } - screen.DrawImage(sprite.Image, op) + if otherplayer == player { + continue + } + + otherposition := (*Position)(system.World.Get(otherplayer, posID)) + + ok, _ := otherposition.Intersects(position, velocity) + if ok { + // keep displaying it until the two fully intersect + EntitiesToRemove = append(EntitiesToRemove, otherplayer) + } } + + // FIXME: add an animation highlighting the fusion + return EntitiesToRemove }