| 
									
										
										
										
											2024-02-25 14:05:44 +01:00
										 |  |  | package systems | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"log/slog" | 
					
						
							|  |  |  | 	"openquell/components" | 
					
						
							|  |  |  | 	. "openquell/components" | 
					
						
							|  |  |  | 	. "openquell/config" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"openquell/grid" | 
					
						
							|  |  |  | 	"openquell/observers" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/hajimehoshi/ebiten/v2" | 
					
						
							|  |  |  | 	"github.com/mlange-42/arche/ecs" | 
					
						
							|  |  |  | 	"github.com/mlange-42/arche/generic" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type DestroyableSystem struct { | 
					
						
							|  |  |  | 	World         *ecs.World | 
					
						
							|  |  |  | 	Selector      *generic.Filter3[Position, Renderable, Destroyable] | 
					
						
							|  |  |  | 	GridContainer *grid.GridContainer | 
					
						
							|  |  |  | 	SolidMapper   generic.Map4[ // needed for replacement | 
					
						
							|  |  |  | 		components.Position, | 
					
						
							|  |  |  | 		components.Renderable, | 
					
						
							|  |  |  | 		components.Tilish, | 
					
						
							|  |  |  | 		components.Solid] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type DoorToRemove struct { | 
					
						
							|  |  |  | 	Entity   ecs.Entity | 
					
						
							|  |  |  | 	Position *components.Position | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewDestroyableSystem(world *ecs.World, gridcontainer *grid.GridContainer) System { | 
					
						
							|  |  |  | 	solidmapper := generic.NewMap4[ | 
					
						
							|  |  |  | 		components.Position, | 
					
						
							|  |  |  | 		components.Renderable, | 
					
						
							|  |  |  | 		components.Tilish, | 
					
						
							|  |  |  | 		components.Solid](world) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	system := &DestroyableSystem{ | 
					
						
							|  |  |  | 		Selector:      generic.NewFilter3[Position, Renderable, Destroyable](), | 
					
						
							|  |  |  | 		World:         world, | 
					
						
							|  |  |  | 		GridContainer: gridcontainer, | 
					
						
							|  |  |  | 		SolidMapper:   solidmapper, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return system | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (system *DestroyableSystem) Update() error { | 
					
						
							| 
									
										
										
										
											2024-02-27 14:45:23 +01:00
										 |  |  | 	observer := observers.GetGameObserver(system.World) | 
					
						
							| 
									
										
										
										
											2024-02-25 14:05:44 +01:00
										 |  |  | 	posID := ecs.ComponentID[components.Position](system.World) | 
					
						
							|  |  |  | 	veloID := ecs.ComponentID[components.Velocity](system.World) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	query := system.Selector.Query(system.World) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	EntitiestoRemove := []*DoorToRemove{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for query.Next() { | 
					
						
							|  |  |  | 		doorposition, renderable, door := query.Get() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-27 14:45:23 +01:00
										 |  |  | 		for _, player := range observer.GetPlayers() { | 
					
						
							| 
									
										
										
										
											2024-02-25 14:19:21 +01:00
										 |  |  | 			if !system.World.Alive(player) { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-25 14:05:44 +01:00
										 |  |  | 			playerposition := (*Position)(system.World.Get(player, posID)) | 
					
						
							|  |  |  | 			playervelocity := (*Velocity)(system.World.Get(player, veloID)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ok, newpos := doorposition.Intersects(playerposition, playervelocity) | 
					
						
							|  |  |  | 			if ok { | 
					
						
							|  |  |  | 				// player bumped into hidden wall, activate it, snap in player | 
					
						
							|  |  |  | 				slog.Debug("bump not die", "originalpos", playerposition) | 
					
						
							|  |  |  | 				playervelocity.Change(Stop) | 
					
						
							|  |  |  | 				playerposition.Set(newpos) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if door.Activated { | 
					
						
							|  |  |  | 					// player bumps into the door a second time, now hide it | 
					
						
							|  |  |  | 					EntitiestoRemove = append(EntitiestoRemove, | 
					
						
							|  |  |  | 						&DoorToRemove{Entity: query.Entity(), Position: doorposition}) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					slog.Debug("activating destroyable", "doorpos", doorposition) | 
					
						
							|  |  |  | 					door.Activated = true | 
					
						
							|  |  |  | 					renderable.Image = door.GetNext() | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, door := range EntitiestoRemove { | 
					
						
							|  |  |  | 		slog.Debug("hiding destroyable", "doorpos", door.Position.Point()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// remove door entity | 
					
						
							|  |  |  | 		system.World.RemoveEntity(door.Entity) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (system *DestroyableSystem) 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) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |