11.4. 飞行小鸟



完整代码
  1# Flappy Bird game for mPython
  2# frok from github.com/zelacerda/micropython ,2017 - by zelacerda
  3# modify from LabPlus@Tangliufeng
  4
  5from mpython import *
  6from framebuf import FrameBuffer
  7import framebuf
  8import time, uos,urandom
  9
 10# 16 x 12
 11BIRD = bytearray([
 12    0x7, 0xe0, 0x18, 0xf0, 0x21, 0xf8, 0x71, 0xec, 0xf9, 0xec, 0xfc, 0xfc, 0xbe, 0x7e, 0x4c, 0x81, 0x71, 0x7e, 0x40,
 13    0x82, 0x30, 0x7c, 0xf, 0x80
 14])
 15
 16# 16 x 32
 17PIPE_TOP = bytearray([
 18    0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20,
 19    0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c,
 20    0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0xff, 0xff, 0x80, 0xf, 0x80,
 21    0xf, 0x80, 0xf, 0x80, 0xf, 0xff, 0xff
 22])
 23PIPE_DOWN = bytearray([
 24    0xff, 0xff, 0x80, 0xf, 0x80, 0xf, 0x80, 0xf, 0x80, 0xf, 0xff, 0xff, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c,
 25    0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20,
 26    0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c,
 27    0x20, 0x1c, 0x20, 0x1c, 0x20, 0x1c
 28])
 29
 30
 31# Bitmap images
 32bird_size = (16, 12)
 33pipe_size = (16, 32)
 34
 35
 36WIDTH = 128
 37HEIGHT = 64
 38
 39
 40"""飞行小鸟类"""
 41class Bird:
 42    def __init__(self):
 43        self.height = bird_size[1]
 44        self.y = HEIGHT // 2 - self.height // 2
 45        self.wing_power = 4
 46        self.gravity = 0.8
 47        self.vel = -self.wing_power
 48
 49    # 下落
 50    def drop(self):
 51        self.vel += self.gravity
 52        self.y = int(self.y + self.vel)
 53
 54    # 飞行
 55    def flap(self):
 56        self.vel = -self.wing_power
 57
 58    # 是否坠落
 59    def crashed(self):                          
 60        y_limit = HEIGHT - self.height
 61        return self.y > y_limit
 62
 63"""障碍类"""
 64class Obstacle:
 65    def __init__(self, x,size ):
 66        self.size =size 
 67        self.gap = urandom.randint(6 + self.size, HEIGHT - 6 - self.size)     # 随机生成间隙大小
 68        self.x = x              # 距离鸟大小
 69        self.score = 0          # 分数
 70        self.rate = 3           # 速率
 71
 72    # 移动
 73    def scroll(self):           
 74        self.x -= self.rate    
 75        if self.x < -pipe_size[0]:
 76            self.score += 1
 77            self.x = WIDTH
 78            self.gap = urandom.randint(6 + self.size, HEIGHT - 6 - self.size)
 79
 80    # 是否碰撞
 81    def collided(self, y):                     
 82        if self.x < bird_size[0] and self.x > -pipe_size[0] and \
 83           (self.gap - y > self.size or y + bird_size[1] - self.gap > self.size):
 84            return True
 85        else:
 86            return False
 87
 88
 89class Game():
 90    def __init__(self,gap_size):
 91        
 92        # 创建鸟和管道的framebuffer
 93        self.bird_fb = FrameBuffer(BIRD, bird_size[0], bird_size[1], framebuf.MONO_HLSB)         
 94        self.pipe_top_fb = FrameBuffer(PIPE_TOP, pipe_size[0], pipe_size[1], framebuf.MONO_HLSB)
 95        self.pipe_down_fb = FrameBuffer(PIPE_DOWN, pipe_size[0], pipe_size[1], framebuf.MONO_HLSB)
 96
 97        self.gap_size = gap_size
 98        self.high_score = 0
 99        self.pressed  = False
100        self.game_state = 0
101        self.flappy_bird =  None
102        self.obstacle_1 =  None
103        self.obstacle_2 =  None
104
105    # 保存最高分
106    def write_high_score(self,n):
107        f = open('fb_high_score.txt', 'w')
108        f.write(str(n))
109        f.close()
110
111    # 读取最高分
112    def read_high_score(self):
113        if 'fb_high_score' in uos.listdir():
114            f = open('fb_high_score.txt', 'r')
115            high_score = f.read()
116            f.close()
117            return int(high_score)
118        else:
119            self.write_high_score(0)
120            return 0
121
122   # 绘制
123    def draw(self):
124        oled.fill(0)
125        oled.blit(self.bird_fb, 0, self.flappy_bird.y)
126        oled.blit(self.pipe_top_fb, self.obstacle_1.x, self.obstacle_1.gap - self.gap_size - pipe_size[1])
127        oled.blit(self.pipe_down_fb, self.obstacle_1.x, self.obstacle_1.gap + self.gap_size)
128        oled.blit(self.pipe_top_fb, self.obstacle_2.x, self.obstacle_2.gap - self.gap_size - pipe_size[1])
129        oled.blit(self.pipe_down_fb, self.obstacle_2.x, self.obstacle_2.gap + self.gap_size)
130        oled.fill_rect(WIDTH // 2 - 13, 0, 26, 9, 0)
131        oled.text('%03d' % (self.obstacle_1.score + self.obstacle_2.score), WIDTH // 2 - 12, 0)
132        oled.show()
133   
134
135    def _clicked(self):
136        if button_a.value() == 0 and not self.pressed:
137            self.pressed = True
138            return True
139        elif button_a.value() == 1 and self.pressed:
140            self.pressed = False
141        return False
142
143    # 开机画面
144    def game_start(self):
145        oled.fill(0)
146        oled.blit(self.pipe_down_fb, (WIDTH - pipe_size[0]) // 2, HEIGHT - 12)
147        oled.blit(self.bird_fb, (WIDTH - bird_size[0]) // 2, HEIGHT - 12 - bird_size[1])
148        oled.rect(0, 0, WIDTH, HEIGHT, 1)
149        oled.text('F L A P P Y', WIDTH // 2 - 44, 3)
150        oled.text('B I R D', WIDTH // 2 - 28, 13)
151        oled.text('Record: ' + '%03d' % self.high_score, WIDTH // 2 - 44, HEIGHT // 2 - 6)
152        oled.show()
153        self.game_state = 1
154      
155    def game_waiting(self):
156        if self._clicked():
157            self.flappy_bird = Bird()                                                               # 实例小鸟对象
158            self.obstacle_1 = Obstacle(WIDTH,self.gap_size)                                           # 实例第一个障碍对象
159            self.obstacle_2 = Obstacle(WIDTH + (WIDTH + pipe_size[0]) // 2,self.gap_size)             # 实例第二个障碍对象
160            self.game_state = 2
161
162    def game_running(self):
163        if self._clicked():
164            self.flappy_bird.flap()
165        self.flappy_bird.drop()
166        if self.flappy_bird.crashed():
167            self.flappy_bird.y = HEIGHT - self.flappy_bird.height      # 边界限制
168            self.game_state = 3
169        self.obstacle_1.scroll()
170        self.obstacle_2.scroll()
171        if self.obstacle_1.collided(self.flappy_bird.y) or self.obstacle_2.collided(self.flappy_bird.y):
172            self.game_state = 3
173        self.draw()
174
175    def game_over(self):
176        oled.fill_rect(WIDTH // 2 - 32, 10, 64, 23, 0)
177        oled.rect(WIDTH // 2 - 32, 10, 64, 23, 1)
178        oled.text('G A M E', WIDTH // 2 - 28, 13)
179        oled.text('O V E R', WIDTH // 2 - 28, 23)
180        self.score = self.obstacle_1.score + self.obstacle_2.score
181        if self.score > self.high_score:
182            self.high_score = self.score
183            oled.fill_rect(WIDTH // 2 - 48, 37, 96, 14, 0)
184            oled.rect(WIDTH // 2 - 48, 37, 96, 14, 1)
185            oled.text('New record!', WIDTH // 2 - 44, 40)
186            self.write_high_score(self.high_score)
187        oled.show()
188
189        try:
190            self.send_score(self.score)
191        except:
192            pass
193        self.game_state = 1
194
195
196    def run(self):
197        while True:
198            if self.game_state == 0: self.game_start()
199            elif self.game_state == 1: self.game_waiting()
200            elif self.game_state == 2: self.game_running()
201            elif self.game_state == 3: self.game_over()
202
203
204
205if __name__ == '__main__':
206    game=Game(gap_size = 16)
207    game.run()
208                
209            
210