package systems import ( "lab.zaar.be/thefish/alchemyst-go/engine/ecs" "lab.zaar.be/thefish/alchemyst-go/engine/fov" "lab.zaar.be/thefish/alchemyst-go/engine/gamestate" "lab.zaar.be/thefish/alchemyst-go/engine/types" "lab.zaar.be/thefish/alchemyst-go/ui/mainwindow" "sort" "time" ) var fovRecompute = true var redraw = false type LevelRenderSystem struct { Viewport *mainwindow.ViewPort Controller *ecs.Controller state *gamestate.GameState layer *mainwindow.Layer fov fov.Fov animateTiles *time.Ticker TorchRadius int } func NewLevelRenderSystem( state *gamestate.GameState, controller *ecs.Controller, vp *mainwindow.ViewPort, layer *mainwindow.Layer, fov fov.Fov, ) LevelRenderSystem { trs := LevelRenderSystem{ Viewport: vp, Controller: controller, layer: layer, state: state, fov: fov, } trs.TorchRadius = 12 //fixme move to sight component trs.animateTiles = time.NewTicker(time.Second / 12) return trs } // fixme add to screens/game Exit() func (trs LevelRenderSystem) Close() { trs.animateTiles.Stop() trs.animateTiles = nil //zero pointer to ticker } func (trs LevelRenderSystem) Listen() { for { select { case <-trs.state.FovRecompute: fovRecompute = true case <-trs.state.Redraw: redraw = true case <-trs.animateTiles.C: redraw = true } } } type priorityRenderable struct { types.Appearance types.Coords Priority int //with bigger are rendered last } type prioritySorter []priorityRenderable func (a prioritySorter) Len() int { return len(a) } func (a prioritySorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a prioritySorter) Less(i, j int) bool { return a[i].Priority < a[j].Priority } func (trs LevelRenderSystem) Process() { playerCoords := trs.state.Controller.GetComponent(trs.state.Player, ecs.CoordsComponent).(types.Coords) trs.Viewport.Move(trs.state, playerCoords) if fovRecompute { trs.layer.ClearRect(trs.Viewport.Rect) trs.fov.ComputeFov(trs.state.Level, playerCoords, trs.TorchRadius) fovRecompute = false redraw = true } if redraw { //terrain for y := 0; y < trs.Viewport.H; y++ { for x := 0; x < trs.Viewport.W; x++ { mapCoords := types.Coords{X: trs.Viewport.CameraCoords.X + x, Y: trs.Viewport.CameraCoords.Y + y} if trs.state.Level.InBounds(mapCoords) { tile := trs.state.Level.GetTile(mapCoords) if tile.Explored || tile.Visible { trs.layer.PutToBase( x+trs.Viewport.X, y+trs.Viewport.Y, tile.GetChar(), tile.GetRawColor(), tile.GetRawBgColor(), ) } } } } //mobs entToRender := make([]priorityRenderable, 0) for e := range trs.Controller.GetEntities() { if trs.Controller.HasComponent(e, ecs.CoordsComponent) && trs.Controller.HasComponent(e, ecs.AppearanceComponent) { pos := trs.Controller.GetComponent(e, ecs.CoordsComponent).(types.Coords) appearance := trs.Controller.GetComponent(e, ecs.AppearanceComponent).(types.Appearance) //fixme fov check if !trs.state.Level.GetTile(pos).Visible { continue } vpc, err := trs.Viewport.ToVPCoords(pos) if err != nil { continue //we cant see it? no problem. } //Костыль для приоритета отрисовки p := 0 if trs.Controller.HasComponent(e, ecs.CarriedComponent) { p = 10 } if trs.Controller.HasComponent(e, ecs.MoveableComponent) { p = 100 } entToRender = append(entToRender, priorityRenderable{ Appearance: appearance, Coords: vpc, Priority: p, }) } } sort.Sort(prioritySorter(entToRender)) for _, ree := range entToRender { trs.layer.WithRawColor(ree.Appearance.ColorSet.Fg.GetColor()). Put(ree.X, ree.Y, ree.Appearance.Glyph.GetGlyph()) } entToRender = nil redraw = false } } func (trs LevelRenderSystem) SystemType() string { return ecs.TerrainRenderSystem }