11.1. 贪吃蛇



完整代码
  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()