From 085b1078d4b805f5f50a7606be65b7a42604c236 Mon Sep 17 00:00:00 2001
From: gmzar <gmzar@mindfire.games>
Date: Wed, 17 Jul 2019 20:05:05 -0700
Subject: [PATCH] Converted to use entity interfaces

---
 entity/entity.go     | 73 +++++++++++++++++++++++++++++++++++---------
 interfaces/entity.go | 17 +++++++++++
 main.go              |  7 +++--
 mapping/gamemap.go   | 46 ++++++++++++++--------------
 render.go            | 14 ++++-----
 5 files changed, 110 insertions(+), 47 deletions(-)
 create mode 100644 interfaces/entity.go

diff --git a/entity/entity.go b/entity/entity.go
index 0a11974..7001eeb 100644
--- a/entity/entity.go
+++ b/entity/entity.go
@@ -1,25 +1,70 @@
 package entity
 
 import (
+	"steel/interfaces"
+
 	"github.com/kettek/goro"
 )
+
 // Entity is a type that represents an active entity in the world.
 type Entity struct {
-	X, Y int
-	Rune rune
-	Style goro.Style
+	x, y  int
+	rune  rune
+	style goro.Style
 }
+
+// NewEntity returns a pointer to a newly created Entity.
+func NewEntity(x int, y int, r rune, s goro.Style) interfaces.Entity {
+	return &Entity{
+		x:     x,
+		y:     y,
+		rune:  r,
+		style: s,
+	}
+}
+
 // Move moves the entity by a given amount.
 func (e *Entity) Move(x, y int) {
-	e.X += x
-	e.Y += y
+	e.x += x
+	e.y += y
+}
+
+// X returns the entity's X value.
+func (e *Entity) X() int {
+	return e.x
+}
+
+// SetX sets the entity's X value
+func (e *Entity) SetX(x int) {
+	e.x = x
+}
+
+// Y returns the entity's Y value.
+func (e *Entity) Y() int {
+	return e.y
+}
+
+// SetY sets the entity's Y value
+func (e *Entity) SetY(y int) {
+	e.y = y
+}
+
+// Rune returns the entity's rune.
+func (e *Entity) Rune() rune {
+	return e.rune
+}
+
+// SetRune sets the entity's rune.
+func (e *Entity) SetRune(r rune) {
+	e.rune = r
+}
+
+// Style returns the entity's style.
+func (e *Entity) Style() goro.Style {
+	return e.style
+}
+
+// SetStyle sets the entity's style.
+func (e *Entity) SetStyle(s goro.Style) {
+	e.style = s
 }
-// NewEntity returns a pointer to a newly created Entity.
-func NewEntity(x int, y int, r rune, s goro.Style) *Entity {
-	return &Entity{
-		X:	x,
-		Y:	y,
-		Rune:	r,
-		Style:	s,
-	}
-}
\ No newline at end of file
diff --git a/interfaces/entity.go b/interfaces/entity.go
new file mode 100644
index 0000000..b6afac4
--- /dev/null
+++ b/interfaces/entity.go
@@ -0,0 +1,17 @@
+package interfaces
+
+import (
+	"github.com/kettek/goro"
+)
+
+type Entity interface {
+	X() int
+	SetX(int)
+	Y() int
+	SetY(int)
+	Rune() rune
+	SetRune(rune)
+	Style() goro.Style
+	SetStyle(goro.Style)
+	Move(int, int)
+}
diff --git a/main.go b/main.go
index 542b046..36c4e22 100644
--- a/main.go
+++ b/main.go
@@ -3,6 +3,7 @@ package main
 import (
 	"log"
 	"steel/entity"
+	"steel/interfaces"
 	"steel/mapping"
 
 	"github.com/kettek/goro"
@@ -40,7 +41,7 @@ func main() {
 		player := entity.NewEntity(screen.Columns/2, screen.Rows/2+5, '@', goro.Style{Foreground: goro.ColorWhite})
 		npc := entity.NewEntity(screen.Columns/2-5, screen.Rows/2, '@', goro.Style{Foreground: goro.ColorYellow})
 
-		entities := []*entity.Entity{
+		entities := []interfaces.Entity{
 			player,
 			npc,
 		}
@@ -59,7 +60,7 @@ func main() {
 		for {
 
 			if fovRecompute {
-				RecomputeFov(fovMap, player.X, player.Y, fovRadius, fov.Light{})
+				RecomputeFov(fovMap, player.X(), player.Y(), fovRadius, fov.Light{})
 			}
 
 			// Draw screen.
@@ -74,7 +75,7 @@ func main() {
 			case goro.EventKey:
 				switch action := handleKeyEvent(event).(type) {
 				case ActionMove:
-					if !gameMap.IsBlocked(player.X+action.X, player.Y+action.Y) {
+					if !gameMap.IsBlocked(player.X()+action.X, player.Y()+action.Y) {
 						player.Move(action.X, action.Y)
 						fovRecompute = true
 					}
diff --git a/mapping/gamemap.go b/mapping/gamemap.go
index 0a3d108..0500dba 100644
--- a/mapping/gamemap.go
+++ b/mapping/gamemap.go
@@ -3,13 +3,13 @@ package mapping
 import (
 	"github.com/kettek/goro"
 
-	"steel/entity"
+	"steel/interfaces"
 )
 
 // GameMap is our map data type.
 type GameMap struct {
 	Width, Height int
-	Tiles			[][]Tile
+	Tiles         [][]Tile
 }
 
 // Initialize initializes a GameMap's Tiles to match its Width and Height. It also sets up some coordinates to block movement and sight.
@@ -20,15 +20,15 @@ func (g *GameMap) Initialize() {
 		g.Tiles[x] = make([]Tile, g.Height)
 		for y := range g.Tiles[x] {
 			g.Tiles[x][y] = Tile{
-				BlockSight:		true,
-				BlockMovement:	true,
+				BlockSight:    true,
+				BlockMovement: true,
 			}
 		}
-	}	
+	}
 }
 
 // MakeMap creates a new randomized map. This is built according to the passed arguments.
-func (g *GameMap) MakeMap(maxRooms, roomMinSize, roomMaxSize int, player *entity.Entity) {
+func (g *GameMap) MakeMap(maxRooms, roomMinSize, roomMaxSize int, player interfaces.Entity) {
 	var rooms []*Rect
 
 	for r := 0; r < maxRooms; r++ {
@@ -40,7 +40,7 @@ func (g *GameMap) MakeMap(maxRooms, roomMinSize, roomMaxSize int, player *entity
 		y := goro.Random.Intn(g.Height - height - 1)
 		// Create a Rect according to our generated sizes.
 		room := NewRect(x, y, width, height)
-	
+
 		// Iterate through our existing rooms to check for intersection with our new room.
 		intersects := false
 		for _, otherRoom := range rooms {
@@ -54,22 +54,22 @@ func (g *GameMap) MakeMap(maxRooms, roomMinSize, roomMaxSize int, player *entity
 			g.CreateRoom(room)
 			roomCenterX, roomCenterY := room.Center()
 
-		// Always place the player in the center of the first room.
-		if len(rooms) == 0 {
-			player.X = roomCenterX
-			player.Y = roomCenterY
-		} else {
-			prevCenterX, prevCenterY := rooms[len(rooms)-1].Center()
-
-			// Flip a coin if we should tunnel horizontally or vertically first.
-			if goro.Random.Intn(1) == 1 {
-				g.CreateHTunnel(prevCenterX, roomCenterX, prevCenterY)
-				g.CreateVTunnel(prevCenterY, roomCenterY, roomCenterX)	
+			// Always place the player in the center of the first room.
+			if len(rooms) == 0 {
+				player.SetX(roomCenterX)
+				player.SetY(roomCenterY)
 			} else {
-				g.CreateVTunnel(prevCenterY, roomCenterY, prevCenterX)
-				g.CreateHTunnel(prevCenterX, roomCenterX, roomCenterY)
+				prevCenterX, prevCenterY := rooms[len(rooms)-1].Center()
+
+				// Flip a coin if we should tunnel horizontally or vertically first.
+				if goro.Random.Intn(1) == 1 {
+					g.CreateHTunnel(prevCenterX, roomCenterX, prevCenterY)
+					g.CreateVTunnel(prevCenterY, roomCenterY, roomCenterX)
+				} else {
+					g.CreateVTunnel(prevCenterY, roomCenterY, prevCenterX)
+					g.CreateHTunnel(prevCenterX, roomCenterX, roomCenterY)
+				}
 			}
-		}
 			// Append our new room to our rooms list.
 			rooms = append(rooms, room)
 		}
@@ -96,7 +96,7 @@ func (g *GameMap) CreateHTunnel(x1, x2, y int) {
 	}
 }
 
-// CreateVTunnel creates a vertical tunnel from y1 to/from y2 starting at x. 
+// CreateVTunnel creates a vertical tunnel from y1 to/from y2 starting at x.
 func (g *GameMap) CreateVTunnel(y1, y2, x int) {
 	for y := goro.MinInt(y1, y2); y <= goro.MaxInt(y1, y2); y++ {
 		if g.InBounds(x, y) {
@@ -115,7 +115,7 @@ func (g *GameMap) IsBlocked(x, y int) bool {
 }
 
 // InBounds returns if the given coordinates are within the map's bounds.
-func (g *GameMap) InBounds (x, y int) bool {
+func (g *GameMap) InBounds(x, y int) bool {
 	if x < 0 || x >= g.Width || y < 0 || y >= g.Height {
 		return false
 	}
diff --git a/render.go b/render.go
index b7277fd..7431fa6 100644
--- a/render.go
+++ b/render.go
@@ -4,12 +4,12 @@ import (
 	"github.com/kettek/goro"
 	"github.com/kettek/goro/fov"
 
-	"steel/entity"
+	"steel/interfaces"
 	"steel/mapping"
 )
 
 // DrawAll draws all entities and the gameMap to the screen and flushes it.
-func DrawAll(screen *goro.Screen, entities []*entity.Entity, gameMap mapping.GameMap, fovMap fov.Map, fovRecompute bool, colors map[string]goro.Color) {
+func DrawAll(screen *goro.Screen, entities []interfaces.Entity, gameMap mapping.GameMap, fovMap fov.Map, fovRecompute bool, colors map[string]goro.Color) {
 	if fovRecompute {
 		// Draw all the riles in the game map.
 		for x, column := range gameMap.Tiles {
@@ -41,18 +41,18 @@ func DrawAll(screen *goro.Screen, entities []*entity.Entity, gameMap mapping.Gam
 }
 
 // ClearAll clears all entities from the screen.
-func ClearAll(screen *goro.Screen, entities []*entity.Entity) {
+func ClearAll(screen *goro.Screen, entities []interfaces.Entity) {
 	for _, entity := range entities {
 		ClearEntity(screen, entity)
 	}
 }
 
 // DrawEntity draws a given entity to the screen.
-func DrawEntity(screen *goro.Screen, e *entity.Entity) {
-	screen.DrawRune(e.X, e.Y, e.Rune, e.Style)
+func DrawEntity(screen *goro.Screen, e interfaces.Entity) {
+	screen.DrawRune(e.X(), e.Y(), e.Rune(), e.Style())
 }
 
 // ClearEntity clears a given entity from the screen.
-func ClearEntity(screen *goro.Screen, e *entity.Entity) {
-	screen.SetRune(e.X, e.Y, ' ')
+func ClearEntity(screen *goro.Screen, e interfaces.Entity) {
+	screen.SetRune(e.X(), e.Y(), ' ')
 }