openquell/observers/game_observer.go

127 lines
3.8 KiB
Go

package observers
import (
"openquell/components"
"log/slog"
"github.com/mlange-42/arche/ecs"
"github.com/mlange-42/arche/ecs/event"
"github.com/mlange-42/arche/generic"
"github.com/mlange-42/arche/listener"
)
// Used for global game state. Also stores mobile entities of the
// current level. The Entities map will be reset on each level
// initialization in grid/grid.go
type GameObserver struct {
World *ecs.World
CurrentLevel, Width int
Height, Cellsize, Score int
StopTimer *components.Timer
Lost bool // set to true if player is struck or something, by default: win!
Retry bool
NextlevelText string
Entities map[ecs.ID]map[ecs.Entity]int
}
func (observer *GameObserver) GetListenerCallback(comp ecs.ID) listener.Callback {
return listener.NewCallback(
func(world *ecs.World, event ecs.EntityEvent) {
observer.RemoveEntity(event.Entity, comp)
slog.Debug("player removed")
},
event.EntityRemoved,
comp,
)
}
func NewGameObserver(world *ecs.World, startlevel, width, height, cellsize int) *GameObserver {
observer := &GameObserver{
CurrentLevel: startlevel,
StopTimer: &components.Timer{},
Width: width,
Height: height,
Cellsize: cellsize,
World: world,
}
resmanger := generic.NewResource[GameObserver](world)
resmanger.Add(observer)
playerID := ecs.ComponentID[components.Player](world)
obstacleID := ecs.ComponentID[components.Obstacle](world)
particleID := ecs.ComponentID[components.Particle](world)
playerListener := observer.GetListenerCallback(playerID)
obstacleListener := observer.GetListenerCallback(obstacleID)
particleListener := observer.GetListenerCallback(particleID)
listen := listener.NewDispatch(
&playerListener,
&obstacleListener,
&particleListener,
)
world.SetListener(&listen)
observer.Entities = make(map[ecs.ID]map[ecs.Entity]int)
observer.Entities[playerID] = make(map[ecs.Entity]int)
observer.Entities[obstacleID] = make(map[ecs.Entity]int)
observer.Entities[particleID] = make(map[ecs.Entity]int)
return observer
}
func GetGameObserver(world *ecs.World) *GameObserver {
observerID := ecs.ResourceID[GameObserver](world)
observer := world.Resources().Get(observerID).(*GameObserver)
return observer
}
func (observer *GameObserver) Gameover() {
observer.Lost = true
}
func (observer *GameObserver) AddEntity(entity ecs.Entity, comp ecs.ID) {
observer.Entities[comp][entity] = 1
}
func (observer *GameObserver) RemoveEntity(entity ecs.Entity, comp ecs.ID) {
delete(observer.Entities[comp], entity)
}
func (observer *GameObserver) GetEntities(comp ecs.ID) []ecs.Entity {
keys := make([]ecs.Entity, 0, len(observer.Entities[comp]))
for k, _ := range observer.Entities[comp] {
keys = append(keys, k)
}
return keys
}
func (observer *GameObserver) GetPlayers() []ecs.Entity {
playerID := ecs.ComponentID[components.Player](observer.World)
return observer.GetEntities(playerID)
}
func (observer *GameObserver) GetObstacles() []ecs.Entity {
obstacleID := ecs.ComponentID[components.Obstacle](observer.World)
return observer.GetEntities(obstacleID)
}
func (observer *GameObserver) GetParticles() []ecs.Entity {
particleID := ecs.ComponentID[components.Particle](observer.World)
return observer.GetEntities(particleID)
}
func (observer *GameObserver) RemoveEntities() {
playerID := ecs.ComponentID[components.Player](observer.World)
obstacleID := ecs.ComponentID[components.Obstacle](observer.World)
particleID := ecs.ComponentID[components.Particle](observer.World)
observer.Entities = make(map[ecs.ID]map[ecs.Entity]int)
observer.Entities[playerID] = make(map[ecs.Entity]int)
observer.Entities[obstacleID] = make(map[ecs.Entity]int)
observer.Entities[particleID] = make(map[ecs.Entity]int)
}