package systems import ( "log/slog" "openquell/assets" "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 TransientSystem struct { World *ecs.World Selector *generic.Filter3[Position, Renderable, Transient] GridContainer *grid.GridContainer SolidMapper generic.Map4[ // needed for replacement components.Position, components.Renderable, components.Tilish, components.Solid] } type TransientToWall struct { Entity ecs.Entity NewSprite string Position components.Position } func NewTransientSystem(world *ecs.World, gridcontainer *grid.GridContainer) System { solidmapper := generic.NewMap4[ components.Position, components.Renderable, components.Tilish, components.Solid](world) system := &TransientSystem{ Selector: generic.NewFilter3[Position, Renderable, Transient](), World: world, GridContainer: gridcontainer, SolidMapper: solidmapper, } return system } func (system *TransientSystem) Update() error { observer := observers.GetGameObserver(system.World) posID := ecs.ComponentID[components.Position](system.World) veloID := ecs.ComponentID[components.Velocity](system.World) query := system.Selector.Query(system.World) EntitiestoMakeSolid := []TransientToWall{} for query.Next() { transientposition, _, transient := query.Get() for _, player := range observer.GetPlayers() { if !system.World.Alive(player) { continue } playerposition := (*Position)(system.World.Get(player, posID)) playervelocity := (*Velocity)(system.World.Get(player, veloID)) ok, _ := transientposition.Intersects(playerposition, playervelocity) if ok { // display the transient sprite as long as the player crosses it transient.Activated = true } else { // the player crossed the transient wall completely if transient.Activated { EntitiestoMakeSolid = append(EntitiestoMakeSolid, TransientToWall{ Entity: query.Entity(), Position: *transientposition, NewSprite: transient.GetNext(), }) slog.Debug("transient added to make solid") } } } } for _, convertible := range EntitiestoMakeSolid { slog.Debug("transient remove") // remove transient entity system.World.RemoveEntity(convertible.Entity) // replace with solid entity slog.Debug("transient add solid") entity := system.SolidMapper.New() pos, render, _, _ := system.SolidMapper.Get(entity) // set it up apropriately pos.Set(&convertible.Position) render.Image = assets.Assets[convertible.NewSprite] // also setup the grid tile with a new solid, so that // collision detection works system.GridContainer.Grid.SetSolidTile( assets.NewTileBlock(convertible.NewSprite), convertible.Position.Point(), ) } return nil } func (system *TransientSystem) Draw(screen *ebiten.Image) { // write transients (these are no tiles!) op := &ebiten.DrawImageOptions{} query := system.Selector.Query(system.World) for query.Next() { pos, render, _ := query.Get() op.GeoM.Reset() op.GeoM.Translate(float64(pos.X), float64(pos.Y)) screen.DrawImage(render.Image, op) } }