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