Skip to content

Commit

Permalink
fix: join terrain columns if possible
Browse files Browse the repository at this point in the history
If two columns with same x position "touch" themselves and there is no hole between them they can be joined to one.

Joining of columns should reduce entities count.
  • Loading branch information
zladovan committed Jul 5, 2020
1 parent 1bed236 commit 2e1075f
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 2 deletions.
6 changes: 6 additions & 0 deletions terrain/column.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,9 @@ func (t *Column) BottomLine() (int, int) {
func (t *Column) MakeHole(cx, cy, r int) {
t.terrain.MakeHole(cx, cy, r)
}

// SetCanvas changes canvas of this column
func (t *Column) SetCanvas(canvas *tl.Canvas) {
t.canvas = canvas
t.Entity.SetCanvas(canvas)
}
2 changes: 1 addition & 1 deletion terrain/cutter.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (c *Cutter) Draw(s *tl.Screen) {
// process all pending cuts
for _, cut := range c.cuts {

// for each x which is should be cut we will create new columns updated by current cut
// for each x which should be cut we will create new columns updated by current cut
newcols := []*Column{}
for _, column := range c.terrain.columns[cut.X] {

Expand Down
67 changes: 67 additions & 0 deletions terrain/joiner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package terrain

import (
tl "github.com/JoelOtter/termloop"
"github.com/zladovan/gorched/debug"
)

// Joiner is responsible for joining terrain columns.
// If two columns with same x position "touch" themselves and there is no hole between them they can be joined to one.
// Joiner is by default not enabled. You need to activate it by calling Enable. Then it will be enabled for 1 second.
type Joiner struct {
// terrain is reference to the terrain which columns will be joined
terrain *Terrain
// ttl is number of seconds till joiner will be not active
ttl float64

}

// Draw will perform joining logic if this joiner is enabled
func (j *Joiner) Draw(s *tl.Screen) {
// early exit if not enabled
if j.ttl <= 0 {
return
}
j.ttl -= s.TimeDelta()

for x, columns := range j.terrain.columns {
// nothing to join
if len(columns) <= 1 {
continue
}

joined := []*Column{columns[0]}
for _, column := range columns[1:] {
last := joined[len(joined)-1]
_, ly := last.Position()
_, lh := last.Size()
_, y := column.Position()

// no need to join
if ly + lh < y {
joined = append(joined, column)
continue
}

// joining
// canvas of last column is added to the canvas of current colum
debug.Logf("Joining terrain columns x=%d y1=%d y2=%d", x, ly, lh)
column.SetCanvas(&tl.Canvas{append((*last.canvas)[0], (*column.canvas)[0]...)})

// replace and remove last column
joined[len(joined) - 1] = column
s.Level().RemoveEntity(last)
}

// replace original columns with joined
j.terrain.columns[x] = joined
}
}

// Tick does nothing now
func (j *Joiner) Tick(e tl.Event) {}

// Enable this joiner for one second
func (j *Joiner) Enable() {
j.ttl = 1
}
6 changes: 5 additions & 1 deletion terrain/terrain.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ type Terrain struct {
columns [][]*Column
// cutter provides terrain destruction logic
cutter *Cutter
// joiner provides terrain columns joining logic
joiner *Joiner
}

// NewTerrain creates new Terrain for given terrain line and height.
Expand All @@ -30,6 +32,7 @@ func NewTerrain(line []int, height int, lowColor bool) *Terrain {
terrain := &Terrain{height: height}
terrain.columns = make([][]*Column, len(line))
terrain.cutter = &Cutter{terrain: terrain}
terrain.joiner = &Joiner{terrain: terrain}

// create column for each point in terrain line
for x, baseY := range line {
Expand Down Expand Up @@ -75,7 +78,7 @@ func (t *Terrain) PositionOn(x int) gmath.Vector2i {

// Entities returns all entities (columns) which is terrain made of
func (t *Terrain) Entities() []tl.Drawable {
entities := []tl.Drawable{t.cutter}
entities := []tl.Drawable{t.cutter, t.joiner}
for _, cs := range t.columns {
for _, c := range cs {
entities = append(entities, c)
Expand All @@ -101,6 +104,7 @@ func (t *Terrain) CutAround(x, y, w int) {
func (t *Terrain) MakeHole(cx, cy, r int) {
debug.Logf("Hole in the terrain centerx=%d, centery=%d", cx, cy)
t.cutter.CutHole(cx, cy, r)
t.joiner.Enable()
}

// Line returns terrain line array where index is x coordinate and value is top y coordinate.
Expand Down

0 comments on commit 2e1075f

Please sign in to comment.