Explorar el Código

#4 Gives the snake a tail.

Sacha Ligthert hace 2 años
padre
commit
aea82ab765
Se han modificado 6 ficheros con 133 adiciones y 40 borrados
  1. 8 4
      apple.go
  2. 19 17
      game.go
  3. 0 9
      main.go
  4. 3 3
      render.go
  5. 88 7
      snake.go
  6. 15 0
      types.go

+ 8 - 4
apple.go

@@ -15,7 +15,8 @@ import (
 // 	return foodsRune[randomIndex]
 // }
 
-func placeApple(snakex *int, snakey *int) Apple {
+// func placeApple(snakex int, snakey int) Apple {
+func placeApple(snake *Snake) Apple {
 	var x, y int
 	var found bool
 
@@ -24,12 +25,15 @@ func placeApple(snakex *int, snakey *int) Apple {
 		x = rand.Intn(80)
 		y = rand.Intn(24)
 
-		if x != *snakex && y != *snakey {
+		if x != snake.head.x && y != snake.head.y {
 			found = true
 		}
 		if x == 0 || x == 79 || y == 0 || y == 23 {
 			found = false
 		}
+		if hitsTail(snake, x, y) {
+			found = false
+		}
 
 	}
 
@@ -42,6 +46,6 @@ func placeApple(snakex *int, snakey *int) Apple {
 
 }
 
-func drawApple(screen tcell.Screen, style tcell.Style, x int, y int) {
-	screen.SetContent(x, y, '🍎', nil, style)
+func drawApple(screen tcell.Screen, style tcell.Style, apple *Apple) {
+	screen.SetContent(apple.x, apple.y, 'o', nil, style)
 }

+ 19 - 17
game.go

@@ -45,12 +45,6 @@ func gameDirector(screen tcell.Screen, style tcell.Style, keypresses chan int, g
 
 	var score int = 0
 	var scoreCounter int = 1
-	//var field [80][24]int
-	// fill up the field:
-	// 0: empty
-	// 1: snake
-	// 2: apple
-	// 3: border
 
 	// Board size
 	var screenx = 80
@@ -63,30 +57,38 @@ func gameDirector(screen tcell.Screen, style tcell.Style, keypresses chan int, g
 	// Last direction we went in
 	var lastpress int = 1
 
-	var apple Apple = placeApple(&snakex, &snakey)
+	var snake Snake = initSnake(&snakex, &snakey)
+	var apple Apple = placeApple(&snake)
 
 	for {
 
 		// Take input or sleep
 		select {
 		case press := <-keypresses:
-			snakeDirection(press, &snakex, &snakey)
+			snakeDirection(press, &snake)
 			lastpress = press
 		case <-time.After(500 * time.Millisecond):
-			snakeDirection(lastpress, &snakex, &snakey)
+			snakeDirection(lastpress, &snake)
 		}
 
-		if snakex == apple.x && snakey == apple.y {
-			apple = placeApple(&snakex, &snakey)
+		if snake.head.x == apple.x && snake.head.y == apple.y {
+			apple = placeApple(&snake)
 			score += scoreCounter
 			scoreCounter++
+			snake.length = 3 + score
 		}
 
 		// Call it quits once the snake hits the border.
-		if snakex == 0 || snakex == screenx-1 {
+		if snake.head.x == 0 || snake.head.x == screenx-1 {
 			close(gamestate)
 			return
-		} else if snakey == 0 || snakey == screeny-1 {
+		} else if snake.head.y == 0 || snake.head.y == screeny-1 {
+			close(gamestate)
+			return
+		}
+
+		// Check if head intersects with any parts of the body
+		if hitsTail(&snake, snake.head.x, snake.head.y) {
 			close(gamestate)
 			return
 		}
@@ -95,10 +97,10 @@ func gameDirector(screen tcell.Screen, style tcell.Style, keypresses chan int, g
 		screen.Clear()
 
 		// Draw the screen
-		drawBox(screen, 0, 0, screenx-1, screeny-1, style)
-		drawCoords(screen, style, &snakex, &snakey)
-		drawApple(screen, style, apple.x, apple.y)
-		drawSnake(screen, style, snakex, snakey)
+		drawBox(screen, style, 0, 0, screenx-1, screeny-1)
+		drawCoords(screen, style, &snake)
+		drawApple(screen, style, &apple)
+		drawSnake(screen, style, &snake)
 		drawScore(screen, style, score)
 
 		// Draw the screen

+ 0 - 9
main.go

@@ -4,15 +4,6 @@ import (
 	"log"
 )
 
-type Position struct {
-	x int
-	y int
-}
-
-type Apple Position
-
-//type Snake Position
-
 func main() {
 
 	// Create channles to manage keypresses and the gamestate

+ 3 - 3
render.go

@@ -26,15 +26,15 @@ func drawScore(screen tcell.Screen, style tcell.Style, score int) {
 	}
 }
 
-func drawCoords(screen tcell.Screen, style tcell.Style, snakex *int, snakey *int) {
+func drawCoords(screen tcell.Screen, style tcell.Style, snake *Snake) {
 	var x, y int = 25, 24
-	for _, r := range []rune("[ x:" + strconv.FormatInt(int64(*snakex), 10) + " y: " + strconv.FormatInt(int64(*snakey), 10) + " ]") {
+	for _, r := range []rune("[ x:" + strconv.FormatInt(int64(*&snake.head.x), 10) + " y: " + strconv.FormatInt(int64(*&snake.head.y), 10) + " ]") {
 		screen.SetContent(x, y-1, r, nil, style)
 		x++
 	}
 }
 
-func drawBox(s tcell.Screen, x1, y1, x2, y2 int, style tcell.Style) {
+func drawBox(s tcell.Screen, style tcell.Style, x1, y1, x2, y2 int) {
 	if y2 < y1 {
 		y1, y2 = y2, y1
 	}

+ 88 - 7
snake.go

@@ -4,18 +4,99 @@ import (
 	"github.com/gdamore/tcell/v2"
 )
 
-func drawSnake(screen tcell.Screen, style tcell.Style, x int, y int) {
-	screen.SetContent(x, y, '🐍', nil, style)
+func initSnake(snakex *int, snakey *int) Snake {
+	var x, y int = *snakex, *snakey
+	snake := Snake{
+		head: Position{
+			x: x,
+			y: y,
+		},
+		tail: []Position{
+			{
+				x: x - 1,
+				y: y,
+			},
+			{
+				x: x - 2,
+				y: y,
+			},
+			{
+				x: x - 3,
+				y: y,
+			},
+		},
+		length:    3,
+		direction: 1,
+	}
+
+	return snake
+}
+
+func drawSnake(screen tcell.Screen, style tcell.Style, snake *Snake) {
+
+	// Reverse tail, chop of the excesses,
+	snake.tail = ReverseSlice(snake.tail)
+	if len(snake.tail) > snake.length {
+		snake.tail = snake.tail[:snake.length]
+	}
+	// reverse it back to the original order, replace the tail in `snake`
+	snake.tail = ReverseSlice(snake.tail)
+
+	// Draw the body
+	for _, segment := range snake.tail {
+		screen.SetContent(segment.x, segment.y, '+', nil, style)
+	}
+
+	// Draw the head, make sure it is on top of everything
+	screen.SetContent(snake.head.x, snake.head.y, '0', nil, style)
+
 }
 
-func snakeDirection(press int, snakex *int, snakey *int) {
+func snakeDirection(press int, snake *Snake) {
 	if press == Left {
-		*snakex--
+		if snake.direction != Right {
+			snake.head.x--
+			snake.tail = append(snake.tail, Position{x: snake.head.x + 1, y: snake.head.y})
+			snake.direction = press
+		}
 	} else if press == Right {
-		*snakex++
+		if snake.direction != Left {
+			snake.head.x++
+			snake.tail = append(snake.tail, Position{x: snake.head.x - 1, y: snake.head.y})
+			snake.direction = press
+		}
 	} else if press == Up {
-		*snakey--
+		if snake.direction != Down {
+			snake.head.y--
+			snake.tail = append(snake.tail, Position{x: snake.head.x, y: snake.head.y + 1})
+			snake.direction = press
+		}
 	} else if press == Down {
-		*snakey++
+		if snake.direction != Up {
+			snake.head.y++
+			snake.tail = append(snake.tail, Position{x: snake.head.x, y: snake.head.y - 1})
+			snake.direction = press
+		}
+	}
+}
+
+// Check if a pos hits the tail
+func hitsTail(snake *Snake, x int, y int) bool {
+	var hit bool = false
+
+	for _, segment := range snake.tail {
+		if segment.x == x && segment.y == y {
+			hit = true
+		}
+	}
+
+	return hit
+}
+
+func ReverseSlice[T comparable](s []T) []T {
+	var r []T
+	for i := len(s) - 1; i >= 0; i-- {
+		r = append(r, s[i])
 	}
+	return r
 }

+ 15 - 0
types.go

@@ -0,0 +1,15 @@
+package main
+
+type Position struct {
+	x int
+	y int
+}
+
+type Apple Position
+
+type Snake struct {
+	head      Position
+	tail      []Position
+	length    int
+	direction int
+}