package mainwindow import ( "errors" "fmt" "lab.zaar.be/thefish/alchemyst-go/engine/fov" "lab.zaar.be/thefish/alchemyst-go/engine/fov/precomputed_shade" "lab.zaar.be/thefish/alchemyst-go/engine/gamestate" "lab.zaar.be/thefish/alchemyst-go/engine/types" "time" ) var NotInViewError = errors.New("not in ViewPort") type ViewPort struct { *types.Rect cameraCoords types.Coords layer *Layer Fov fov.Fov TorchRadius int animateTiles *time.Ticker } func NewViewPort(x, y, w, h int, layer *Layer) *ViewPort { computedFov := precomputed_shade.NewPrecomputedShade(15) computedFov.Init() vp := ViewPort{ Rect: &types.Rect{x, y, w, h}, layer: layer, Fov: computedFov, } vp.TorchRadius = 12 vp.animateTiles = time.NewTicker(time.Second / 12) return &vp } func (vp *ViewPort) Close() { vp.animateTiles.Stop() vp.animateTiles = nil //free pointer to ticker } func (vp *ViewPort) Move(state *gamestate.GameState, newCoords types.Coords) { x := newCoords.X - vp.Rect.W/2 y := newCoords.Y - vp.Rect.H/2 if x < 0 { x = 0 } if y < 0 { y = 0 } if x > state.Level.W - vp.W - 1 { x = state.Level.W - vp.W } if y > state.Level.H-vp.H - 1 { y = state.Level.H - vp.H } if x != vp.cameraCoords.X || y != vp.cameraCoords.Y { state.FovRecompute <- struct{}{} } vp.cameraCoords.X = x vp.cameraCoords.Y = y } func (vp *ViewPort) ToVPCoords(c types.Coords) (newCoords types.Coords, err error) { //coords on map to coords on vp x, y := c.X-vp.cameraCoords.X, c.Y-vp.cameraCoords.Y if x < 0 || y < 0 || x > vp.W || y > vp.H { return types.Coords{-1, -1}, NotInViewError } return types.Coords{x, y}, nil } var redraw = true var fovRecompute = true func (vp *ViewPort) Listen(state gamestate.GameState) { for { select { case <-state.FovRecompute: fovRecompute = true case <-state.Redraw: redraw = true case <-vp.animateTiles.C: redraw = true } } } func (vp *ViewPort) Render(state *gamestate.GameState) { playerCoords := state.Controller.GetComponent(state.Player, types.Coords{}.TypeOf()).(types.Coords) vp.Move(state, playerCoords) if fovRecompute { vp.layer.ClearRect(vp.Rect) fovRecompute = false redraw = true vp.Fov.ComputeFov(state.Level, playerCoords, vp.TorchRadius) } vp.layer.ClearArea(0, 7, 20, 1) vp.layer.Print(0,7, fmt.Sprintf("pcds: %v", playerCoords)) if redraw { //terrain for y := 0; y < vp.H; y++ { for x := 0; x < vp.W; x++ { mapCoords := types.Coords{vp.cameraCoords.X + x, vp.cameraCoords.Y + y} if state.Level.InBounds(mapCoords) { tile := state.Level.GetTile(mapCoords) if tile.Explored || tile.Visible { vp.layer.PutToBase(x+vp.X, y+vp.Y, tile.GetChar(), tile.GetRawColor(), tile.GetRawBgColor()) } } } } //mobs pc, err := vp.ToVPCoords(playerCoords) _ = pc if err != nil { fmt.Println("error on getting player position") } else { vp.layer.WithColor("white").Put(pc.X+vp.X, pc.Y+vp.Y, "@") //mw.GetLayer("base").WithColor("white").Put(42, 10, "B") //mw.GetLayer("overlay").WithColor("white").Put(59, 10, "O") } //redraw = true redraw = false } }