alchemyst/ui/mainwindow/viewport.go
2019-11-12 14:52:17 +03:00

143 lines
3.1 KiB
Go

package mainwindow
import (
"errors"
"fmt"
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
"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, ecs.CoordsComponent).(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
}
}