package systems import ( "openquell/components" . "openquell/components" "openquell/grid" "openquell/observers" "github.com/hajimehoshi/ebiten/v2" "github.com/mlange-42/arche/ecs" "github.com/mlange-42/arche/generic" ) type CollisionSystem struct { World *ecs.World Selector *generic.Filter4[Position, Velocity, Renderable, Collider] GridContainer *grid.GridContainer } func NewCollisionSystem(world *ecs.World, gridcontainer *grid.GridContainer) System { system := &CollisionSystem{ Selector: generic.NewFilter4[Position, Velocity, Renderable, Collider](), GridContainer: gridcontainer, World: world, } return system } func (system CollisionSystem) Update() error { entityobserver := observers.GetEntityObserver(system.World) posID := ecs.ComponentID[components.Position](system.World) EntitiesToRemove := []ecs.Entity{} query := system.Selector.Query(system.World) for query.Next() { position, velocity, _, handler := query.Get() if velocity.Moving() { // check if we bump agains the screen edge ok, newpos := system.GridContainer.Grid.BumpEdge(position, velocity) if ok { if handler.EdgeHandler != nil { if !handler.EdgeHandler(system.World, position, newpos, velocity, query.Entity()) { EntitiesToRemove = append(EntitiesToRemove, query.Entity()) } } } else { // check if we collide with some solid entity ok, tilepos := system.GridContainer.Grid.GetSolidNeighborPosition(position, velocity, true) if ok { intersects, newpos := tilepos.Intersects(position, velocity) if intersects { if handler.CollisionHandler != nil { if !handler.CollisionHandler(system.World, position, newpos, velocity, query.Entity()) { EntitiesToRemove = append(EntitiesToRemove, query.Entity()) } } } } } // check if current entity bumps into another entity for foreign_entity := range entityobserver.Entities { if foreign_entity == query.Entity() { // don't check entity against itself continue } foreign_position := (*Position)(system.World.Get(foreign_entity, posID)) ok, newpos := foreign_position.Intersects(position, velocity) if ok { if handler.CollisionHandler != nil { if !handler.CollisionHandler(system.World, position, newpos, velocity, foreign_entity) { EntitiesToRemove = append(EntitiesToRemove, query.Entity()) } } } } } } for _, entity := range EntitiesToRemove { system.World.RemoveEntity(entity) } return nil } func (system *CollisionSystem) Draw(screen *ebiten.Image) {}