-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgame.go
123 lines (99 loc) · 2.18 KB
/
game.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package main
import (
"errors"
"github.com/gdamore/tcell"
"os"
"slices"
"time"
)
type GameState int
const (
InitialGameState GameState = iota
RunningGameState
PausedGameState
LostGameState
)
var (
GameOverErr = errors.New("game over")
)
type Game struct {
state GameState
board *Board
score int
numFoods int
}
func NewGame(board *Board, numFoods int) *Game {
return &Game{
state: InitialGameState,
board: board,
score: 0,
numFoods: numFoods,
}
}
func (g *Game) Start() error {
var (
err error
)
for i := 0; i < g.numFoods; i++ {
if err = g.board.createFood(); err != nil {
return err
}
}
g.state = RunningGameState
go g.handleInput()
tick := time.Tick(33 * time.Millisecond)
for {
select {
case <-tick:
if err = g.update(); err != nil {
return err
}
g.render()
}
}
}
func (g *Game) update() error {
snakeTail := g.board.snake.tail()
nextSnakeHead := g.board.snake.nextHead()
w, h := g.board.screen.Size()
if g.board.snake.isIn(nextSnakeHead.x, nextSnakeHead.y) || (nextSnakeHead.x <= 0 || nextSnakeHead.x >= w-1) || (nextSnakeHead.y <= 0 || nextSnakeHead.y >= h-1) {
g.state = LostGameState
return GameOverErr
}
g.board.snake.move(nextSnakeHead)
foodIndex := slices.Index(g.board.foods, nextSnakeHead)
if foodIndex != -1 {
g.board.snake.grow(snakeTail)
g.score++
eatenFood := g.board.foods[foodIndex]
g.board.screen.SetContent(eatenFood.x, eatenFood.y, ' ', nil, tcell.StyleDefault)
g.board.foods = slices.Delete(g.board.foods, foodIndex, foodIndex+1)
if err := g.board.createFood(); err != nil {
return err
}
} else {
g.board.screen.SetContent(snakeTail.x, snakeTail.y, ' ', nil, tcell.StyleDefault)
}
return nil
}
func (g *Game) render() {
g.board.draw()
}
func (g *Game) handleInput() {
for {
switch ev := g.board.screen.PollEvent().(type) {
case *tcell.EventResize:
g.board.resize()
case *tcell.EventKey:
if ev.Key() == tcell.KeyEscape || ev.Key() == tcell.KeyCtrlC {
g.board.screen.Fini()
os.Exit(0)
}
if direction, ok := keyToDirection[ev.Key()]; ok {
if g.board.snake.isValidDirection(direction) {
g.board.snake.setDirection(direction)
}
}
}
}
}