1# Snake game for mPython
2# MIT license,Copyright (c) 2019 labplus@Tangliufeng
3
4from mpython import *
5import random, time
6
7WIDTH, HEIGHT = 127, 63
8
9
10class Direction():
11 """
12 贪吃蛇方向,含上下左右
13 """
14
15 UP = 0
16 DOWN = 1
17 LEFT = 2
18 RIGHT = 3
19
20
21class GameState():
22 """
23 游戏状态
24 """
25 PLAYING = 0
26 PAUSE = 1
27 WIN = 2
28 FAIL = 3
29
30
31class Snake():
32 """
33 贪吃蛇
34
35 构建snake
36
37 :param cube(int): 网格大小默认4
38 """
39
40 def __init__(self, cube=4):
41
42 self.cube_width = cube
43 self.grid_width_num, self.grid_height_num = WIDTH // self.cube_width, HEIGHT // self.cube_width
44 self.snake_body = []
45 self.snake_body.append((int(self.grid_width_num // 2 * self.cube_width),
46 int(self.grid_height_num // 2 * self.cube_width))) # 添加贪吃蛇的“头”
47 self.food_pos = self.generate_food()
48 self.direction = Direction.LEFT
49
50 def draw_grids(self):
51 """
52 绘制网格
53 """
54 for i in range(self.grid_width_num + 1):
55 oled.vline(self.cube_width * i, 0, HEIGHT, 1)
56
57 for i in range(self.grid_height_num + 1):
58 oled.hline(0, self.cube_width * i, WIDTH, 1)
59
60 def draw_body(self):
61 """
62 绘制snake
63 """
64 for sb in self.snake_body:
65 # pygame.draw.rect(screen, WHITE, (sb[0], sb[1], CUBE_WIDTH, CUBE_WIDTH))
66 oled.fill_rect(sb[0], sb[1], self.cube_width, self.cube_width, 1)
67
68 def generate_food(self):
69 """
70 随机产生一个食物
71 """
72 self.food_pos = (random.randint(0, self.cube_width - 1), random.randint(0, self.grid_height_num - 1))
73 return self.food_pos
74
75 def draw_food(self):
76 """
77 绘制食物
78 """
79 oled.fill_rect(self.food_pos[0] * self.cube_width, self.food_pos[1] * self.cube_width, self.cube_width,
80 self.cube_width, 1)
81
82 def grow(self):
83 """
84 判断贪吃蛇是否吃到了事物,如果吃到了我们就加长小蛇的身体
85 """
86 if self.snake_body[0][0] == self.food_pos[0] * self.cube_width and \
87 self.snake_body[0][1] == self.food_pos[1] * self.cube_width:
88 return True
89
90 return False
91
92 def refresh(self):
93 """
94 更新小蛇身体的位置
95 """
96 for i in range(len(self.snake_body) - 1, 0, -1):
97 self.snake_body[i] = self.snake_body[i - 1]
98
99 def move(self):
100 """
101 移动snake身体
102 """
103 if self.direction == Direction.UP:
104 self.snake_body[0] = (self.snake_body[0][0], self.snake_body[0][1] - self.cube_width)
105
106 elif self.direction == Direction.DOWN:
107 self.snake_body[0] = (self.snake_body[0][0], self.snake_body[0][1] + self.cube_width)
108
109 # top += cube_width
110 elif self.direction == Direction.LEFT:
111
112 self.snake_body[0] = (self.snake_body[0][0] - self.cube_width, self.snake_body[0][1])
113
114 # left -= cube_width
115 elif self.direction == Direction.RIGHT:
116 self.snake_body[0] = (self.snake_body[0][0] + self.cube_width, self.snake_body[0][1])
117
118
119class Game():
120 """
121 snake游戏控制
122 """
123
124 def __init__(self, fps=8):
125 self.snake = Snake()
126 self.get_body = self.snake.snake_body
127 self.state = None
128 self.fps = fps
129 self.handles_cb = None
130
131 def is_win(self):
132 """
133 判断是否赢
134 """
135 return len(self.get_body) == WIDTH * HEIGHT - 1
136
137 def is_fail(self):
138 """
139 判断是否输
140 """
141 if not 0 <= self.get_body[0][0] < WIDTH or not 0 <= self.get_body[0][1] < HEIGHT:
142 return True
143
144 return False
145
146 @property
147 def score(self):
148 """
149 游戏分数
150 """
151 return len(self.get_body) - 1
152
153 def handles_accele(self, threshold=0.2):
154 """
155 掌控板加速度控制
156 """
157 x = accelerometer.get_x()
158 y = accelerometer.get_y()
159 if y <= 1 and y >= -1:
160 if abs(y) > threshold:
161 if y > 0:
162 self.snake.direction = Direction.LEFT
163 else:
164 self.snake.direction = Direction.RIGHT
165 if x <= 1 and x >= -1:
166 if abs(x) > threshold:
167 if x > 0:
168 self.snake.direction = Direction.DOWN
169 else:
170 self.snake.direction = Direction.UP
171
172 def handles_callback(self, f):
173 """
174 游戏控制回调函数,可外部自定义控制方式
175 """
176 self.handles_cb = f
177
178 def run(self):
179 """
180 游戏运行
181 """
182 self.state = GameState.PLAYING
183 update_time = time.ticks_ms()
184
185 while self.state == GameState.PLAYING: # 游戏状态为PLAYING
186
187 self.handles_cb() # 游戏控制回调函数
188
189 # 显示帧刷新,刷新方块位置
190 if time.ticks_diff(time.ticks_ms(), update_time) > (1000 // self.fps):
191
192 last_pos = self.get_body[-1] # 这里需要保存一下尾部的位置,如果小蛇迟到了食物,需要在尾部增长
193
194 self.snake.refresh() # 更新小蛇身体的位置
195 self.snake.move() # 改变头部的位置
196
197 if self.snake.grow(): # 判断小蛇是否吃到了事物,吃到了就成长,如果吃到了事物我们就产生一个新的食物
198 self.snake.generate_food()
199 self.get_body.append(last_pos)
200
201 oled.fill(0) # 清屏
202 self.snake.draw_body() # 画小蛇的身体
203 self.snake.draw_food() # 画出食物
204
205 oled.show() # 显示生效
206 update_time = time.ticks_ms() # 刷新帧时间
207
208 if self.is_fail(): # 判断if输
209 self.state = GameState.FAIL
210 break
211 if self.is_win(): # 判断if赢
212 self.state = GameState.WIN
213 break
214
215 if self.state == GameState.FAIL: # 输了,显示分数
216 oled.fill(0)
217 oled.text('Game over!', 25, 20)
218 oled.text('Score:%d' % self.score, 25, 32)
219 oled.show()
220
221 if self.state == GameState.WIN: # 赢了!
222 oled.fill(0)
223 oled.text('You win!', 25, 20)
224 oled.show()
225
226
227if __name__ == '__main__':
228 game = Game(fps=8)
229 game.handles_callback(game.handles_accele)
230 game.run()