From bbbe873ff75292e0418616242f6f8e3f4c5eeb66 Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Fri, 9 Feb 2024 20:20:13 +0100 Subject: [PATCH] added systems (not used yet, see TODO) --- TODO.md | 6 +++ game/collectible_system.go | 54 +++++++++++++++++++++++++ game/levels.go | 11 +++++ game/particle_system.go | 53 ++++++++++++++++++++++++ game/player_system.go | 83 ++++++++++++++++++++++++++++++++++++++ systems/system.go | 8 ++++ 6 files changed, 215 insertions(+) create mode 100644 game/collectible_system.go create mode 100644 game/particle_system.go create mode 100644 game/player_system.go create mode 100644 systems/system.go diff --git a/TODO.md b/TODO.md index 9b8cfad..471ec89 100644 --- a/TODO.md +++ b/TODO.md @@ -8,3 +8,9 @@ - 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 + +SYSTEM Stuff: + +- initialize systems in NewLevel() +- replace level.Update() with systems update +- mv Draw() from level to systems diff --git a/game/collectible_system.go b/game/collectible_system.go new file mode 100644 index 0000000..763443e --- /dev/null +++ b/game/collectible_system.go @@ -0,0 +1,54 @@ +package game + +import ( + "fmt" + "image" + . "openquell/components" + + "github.com/mlange-42/arche/ecs" + "github.com/mlange-42/arche/generic" +) + +type CollectibleSystem struct { + World *ecs.World + Selector *generic.Filter2[Position, Collectible] +} + +func NewCollectibleSystem(world *ecs.World) *CollectibleSystem { + system := &CollectibleSystem{ + Selector: generic.NewFilter2[Position, Collectible](), + } + + return system +} + +func (system *CollectibleSystem) CheckPlayerCollision( + playerposition *Position, + playervelocity *Velocity) (bool, image.Point) { + + toRemove := []ecs.Entity{} + particle_pos := image.Point{} + var bumped bool + + query := system.Selector.Query(system.World) + + for query.Next() { + colposition, collectible := query.Get() + + ok, _ := playerposition.Intersects(colposition, playervelocity) + if ok { + fmt.Printf("bumped into collectible %v\n", collectible) + toRemove = append(toRemove, query.Entity()) + particle_pos.X = colposition.X + particle_pos.Y = colposition.Y + bumped = true + } + } + + // remove collectible if collected + for _, entity := range toRemove { + system.World.RemoveEntity(entity) + } + + return bumped, particle_pos +} diff --git a/game/levels.go b/game/levels.go index 171bd15..c2e9a14 100644 --- a/game/levels.go +++ b/game/levels.go @@ -260,6 +260,17 @@ func (level *Level) DrawParticles(screen *ebiten.Image) { } func (level *Level) SetupGrid(game *Game) { + // generic variant does not work here: + // selector := generic.NewFilter1[components.Position]() + // level.World.Batch().RemoveEntities(selector) + // missing argument in conversion to generic.Filter1[components.Position] + + // erase all entities of previous level, if any + posID := ecs.ComponentID[components.Position](level.World) + selector := ecs.All(posID) + level.World.Batch().RemoveEntities(selector) + + // setup world level.Grid = NewGrid(game, level.Cellsize, level.Mapslice) } diff --git a/game/particle_system.go b/game/particle_system.go new file mode 100644 index 0000000..4012854 --- /dev/null +++ b/game/particle_system.go @@ -0,0 +1,53 @@ +package game + +import ( + "image" + . "openquell/components" + + "github.com/mlange-42/arche/ecs" + "github.com/mlange-42/arche/generic" +) + +type ParticleSystem struct { + World *ecs.World + Selector *generic.Filter2[Position, Particle] + Cellsize int +} + +func NewParticleSystem(world *ecs.World) *ParticleSystem { + system := &ParticleSystem{ + Selector: generic.NewFilter2[Position, Particle](), + } + + return system +} + +func (system *ParticleSystem) Update(detonate bool, position *image.Point) { + // display debris after collecting + query := system.Selector.Query(system.World) + + for query.Next() { + // we loop, but it's only one anyway + ptposition, particle := query.Get() + + if detonate { + // particle appears + ptposition.Update( + position.X-(system.Cellsize/2), + position.Y-(system.Cellsize/2), + 64, + ) + + particle.Index = 0 // start displaying the particle + } else { + switch { + // particle shows from earlier tick, animate + case particle.Index > -1 && particle.Index < len(particle.Particles)-1: + particle.Index++ + default: + // last sprite reached, remove it + particle.Index = -1 + } + } + } +} diff --git a/game/player_system.go b/game/player_system.go new file mode 100644 index 0000000..24ff20d --- /dev/null +++ b/game/player_system.go @@ -0,0 +1,83 @@ +package game + +import ( + "fmt" + "image" + . "openquell/components" + . "openquell/config" + + "github.com/hajimehoshi/ebiten/v2" + "github.com/mlange-42/arche/ecs" + "github.com/mlange-42/arche/generic" +) + +type PlayerSystem struct { + World *ecs.World + Grid *Grid + Selector *generic.Filter3[Position, Velocity, Player] + Particle *ParticleSystem + Collectible *CollectibleSystem +} + +func NewPlayerSystem(world *ecs.World) *PlayerSystem { + + system := &PlayerSystem{ + Selector: generic.NewFilter3[Position, Velocity, Player](), + } + + return system +} + +func (system PlayerSystem) Update() error { + query := system.Selector.Query(system.World) + + var bumped bool + var particle_pos image.Point + + for query.Next() { + playerposition, velocity, _ := query.Get() + + 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) + // other keys: : switch player, etc + } + } + + if velocity.Moving() { + ok, newpos := system.Grid.BumpEdge(playerposition, velocity) + if ok { + fmt.Printf("falling off the edge, new pos: %v\n", newpos) + playerposition.Set(newpos) + } else { + ok, tilepos := system.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) + } + } + } + + bumped, particle_pos = system.Collectible.CheckPlayerCollision(playerposition, velocity) + } + + } + + system.Particle.Update(bumped, &particle_pos) + + return nil +} diff --git a/systems/system.go b/systems/system.go new file mode 100644 index 0000000..92d37df --- /dev/null +++ b/systems/system.go @@ -0,0 +1,8 @@ +package system + +import "github.com/hajimehoshi/ebiten/v2" + +type System interface { + Update() error + Draw(screen *ebiten.Image) +}