Python3 pygame实现flappy bird游戏

之前一直在手机上玩flappy bird游戏,闲暇时间就编写了一个

是采用python3+pygame模块制作而成的,运行效果非常流畅,会让你大吃一惊哦😃哈哈

一、运行效果展示

下载游戏之后,注意在自己的python环境中安装pygame模块,如果没有安装可以使用pip install pygame 进行安装

然后使用使用命令运行起这个.py文件,运行之后的第一个界面效果如下,是不是很酷炫

Python3+pygame实现的flappy bird游戏,代码完整,还有音乐

当点击上图中的“Play”按钮之后的效果如下:

Python3+pygame实现的flappy bird游戏,代码完整,还有音乐

运行之后是有音乐的,大家可以下载代码的时候一起将素材下载,这样就在运行时就能听到音乐

二、完整代码

下面代码用到了素材(背景图片,音乐等,下载地址 https://www.itprojects.cn/detail.html?example_id=8af93ac601523a955f8280c95c2a9e0b)

  1 import math

2 import os

3 import time

4 from random import randint

5 from random import uniform

6 import pygame

7 from pygame.locals import * #导入一些常用的变量

8 from collections import deque#加入了队列

9

10 FPS = 60

11 BK_WIDTH = 900 #背景宽度

12 BK_HEIGHT = 650 #背景高度

13 PIPE_WIDTH = 80 #水管的宽度

14 PIPE_HEIGHT = 10 #水管素材的高度

15 PIPE_HEAD_HEIGHT = 32#管子头的高度

16

17 #初始化全局变量

18 BK_MOVE_SPEED = 0.22#主柱子每毫秒移动的速度

19 ADD_TIME = 2500##每隔多少毫秒就增加一个柱子 这种方法不会有漏洞吗 就是当毫秒数和帧数不匹配啥的 #还需要仔细的思考

20 TOTAL_PIPE_BODY = int(3/5 * BK_HEIGHT) # 像素值必须为整数 占窗口的3/5

21 PIPE_RATE =0.96

22 a_i="bird-wingup"

23 b_i="bird-wingmid"

24 c_i="bird-wingdown"

25

26 INITAL_SPEED = -0.37#鸟的Y轴初速度

27 BIRD_WIDTH = 50

28 BIRD_HEIGHT = 40

29 BIRD_INIT_SCORE = 7#鸟的初始通关分数

30

31 STONE_ADD_TIME = 1000 #每隔多少毫秒就增加一个石头

32 STONE_WIDTH = 40

33 STONE_HEIGHT = 30

34 STONE_LEVEL = 4#石头出现的等级

35

36 BUTTON_WIDTH = 140

37 BUTT0N_HEIGHT = 60

38

39 BULLET_SPEED = 0.32#子弹的速度

40 BULLET_WIETH = 50

41 BULLET_HEIGHT = 30

42 #设置全局变量 方便修改参数

43

44

45 pygame.init()

46 screen = pygame.display.set_mode((BK_WIDTH,BK_HEIGHT))

47 pygame.mixer.init()

48

49 music_lose = pygame.mixer.Sound("lose.wav")

50 music1 = pygame.mixer.Sound("touch.wav")

51 pygame.mixer.music.load("bkm.mp3")

52 font = pygame.font.SysFont('comicsansms', 25)

53

54

55 #用于设置鸟的种类

56 def little_bird(list):

57 global a_i

58 global b_i

59 global c_i

60 a_i=list[0]

61 b_i=list[1]

62 c_i=list[2]

63

64

65 #用于设置关卡难度

66 def seteasy(list):

67 global BK_MOVE_SPEED # 背景每毫秒移动的速度 就是柱子移动的速度

68 global ADD_TIME # 每隔多少毫秒就增加一个柱子

69 global TOTAL_PIPE_BODY # 像素值必须为整数 占窗口的3/5

70 global PIPE_RATE

71 global STONE_LEVEL # 鸟出现的等

72 global BIRD_INIT_SCORE

73

74 BK_MOVE_SPEED = list[0] # 背景每毫秒移动的速度

75 ADD_TIME = list[1] # 每隔多少毫秒就增加一个柱子

76 TOTAL_PIPE_BODY =list[2] # 像素值必须为整数 占窗口的3/5

77 PIPE_RATE = list[3]

78 Pipe.add_time = list[1]

79 BIRD_INIT_SCORE = list[4]

80 STONE_LEVEL = list[5]

81

82

83 #子弹类

84 class Bullet(pygame.sprite.Sprite):

85 speed = BULLET_SPEED

86 width = BULLET_WIETH

87 height = BULLET_HEIGHT

88

89 def __init__(self,bird,images):

90 super(Bullet,self).__init__() #d调用父类的初始函数 使用此方法 可以减少代码的更改量 并且解决了多重继承的问题

91 self.x,self.y = bird.x,bird.y

92 self.bullet = images #给鸟的图片进行赋值

93 self.mask_bullet = pygame.mask.from_surface(self.bullet)

94 def update(self):#计算鸟在下一点的新坐标并更新

95 self.x=self.x+self.speed*frames_to_msec(1)

96 @property

97 def image(self):

98 return self.bullet

99 @property

100 def mask(self):

101 return self.mask_bullet

102 @property

103 def rect(self):

104 return Rect(self.x,self.y,Bullet.width,Bullet.height)

105 def visible(self):

106 return 0<self.x<BK_WIDTH+Bullet.width

107

108

109 #小鸟做竖直上抛运动 当小鸟加速到一定状态时 就不再加速了

110 class Bird(pygame.sprite.Sprite):

111

112 width =BIRD_WIDTH #鸟宽

113 height = BIRD_HEIGHT #鸟长

114 sink_gravity = 0.001#鸟的下降重力

115

116 def __init__(self,x,y,level,images):

117 super(Bird,self).__init__() #d调用父类的初始函数 使用此方法 可以减少代码的更改量 并且解决了多重继承的问题

118 self.x,self.y = x,y

119 self.wing_up,self.wing_mid,self.wing_down = images #给鸟的图片进行赋值

120 self.mask_wing_up = pygame.mask.from_surface(self.wing_up)

121 self.mask_wing_mid = pygame.mask.from_surface(self.wing_mid)

122 self.mask_wing_down = pygame.mask.from_surface(self.wing_down)

123 self.inital_speed = 0 #鸟向上的初速度

124 self.level = level #鸟的初始等级

125 self.score = 0 #鸟的初始分数为 0

126

127 def update(self,t):#计算鸟在下一点的新坐标并更新

128 y_ = self.inital_speed*t+0.5*self.sink_gravity*t*t

129 if self.inital_speed<=0.3:

130 self.inital_speed = self.inital_speed +self.sink_gravity*t

131 self.y+=y_ #在主函数里计算时间

132

133 @property

134 def image(self):

135 if pygame.time.get_ticks()%400>=120:

136 return self.wing_up

137 elif pygame.time.get_ticks()%400>=280:

138 return self.wing_mid

139 else:

140 return self.wing_down

141 @property

142 def mask(self):

143 if pygame.time.get_ticks()%400>=120:

144 return self.mask_wing_up

145 elif pygame.time.get_ticks()%400>=280:

146 return self.mask_wing_mid

147 else:

148 return self.mask_wing_down

149

150 @property

151 def rect(self):

152 return Rect(self.x,self.y,Bird.width,Bird.height)

153

154

155

156 class Pipe(pygame.sprite.Sprite):

157 width = PIPE_WIDTH

158 pipe_head_height = PIPE_HEAD_HEIGHT

159 add_time = ADD_TIME

160

161 def __init__(self,pipe_head_image,pipe_body_image):

162 super(Pipe, self).__init__()

163 self.x = float(BK_WIDTH-1)

164 self.score_count = False

165 self.image = pygame.Surface((Pipe.width,BK_HEIGHT),SRCALPHA)#创建一个surface 我理解为能画到窗口上的对象

166 # #意为创建一个有ALPHA 通道的surface 如果需要透明就需要这个选项

167 self.image.convert()

168 self.image.fill((0,0,0,0))#前三位是颜色 最后一位是透明度

169 total_pipe_length = TOTAL_PIPE_BODY

170

171 self.bottom_length = randint(int(0.1*total_pipe_length),int(0.8*total_pipe_length))#用于生成指定范围内的整数

172 self.top_length = total_pipe_length-self.bottom_length

173

174 for i in range(1,self.bottom_length+1):

175 pos = (0,BK_HEIGHT - i)

176 self.image.blit (pipe_body_image,pos)#用重叠的技术画出来管子

177

178 bottom_head_y = BK_HEIGHT - self.bottom_length-self.pipe_head_height #求出管子头的长度

179 bottom_head_pos = (0,bottom_head_y)

180 self.image.blit(pipe_head_image,bottom_head_pos)#画管子

181

182 for i in range(-PIPE_HEIGHT,self.top_length-PIPE_HEIGHT):

183 pos = (0,i)

184 self.image.blit(pipe_body_image,pos)

185 top_head_y = self.top_length

186 self.image.blit(pipe_head_image,(0,top_head_y))

187

188 self.mask = pygame.mask.from_surface(self.image)

189 @property

190 def rect(self):

191 return Rect(self.x,0,Pipe.width,PIPE_HEIGHT)

192 @property

193 def visible(self):

194 return -Pipe.width<self.x<BK_WIDTH

195

196 def update(self,delta_frames=1):

197 self.x-=BK_MOVE_SPEED*frames_to_msec(delta_frames)

198

199 def collides(self,bird):

200 return pygame.sprite.collide_mask(self,bird)

201

202

203 def change_add_time():

204 Pipe.add_time= int( (Pipe.add_time*PIPE_RATE) /100)*100

205 #改变管子的增加时间

206

207

208 #石头具有速度 位置等不同属性

209 #起始的x属性为固定值 y随机 速度在一定范围内随机

210 class Stone(pygame.sprite.Sprite):

211 add_time = STONE_ADD_TIME

212 width = STONE_WIDTH

213 height = STONE_HEIGHT

214 def __init__(self,image):

215 super(Stone, self).__init__()

216 self.x =BK_WIDTH-5

217 self.y = randint(1,int(0.95*BK_HEIGHT))

218 self.speed = uniform(0.1 ,0.5)

219 self.stone_image = image

220 self.mask_image = pygame.mask.from_surface(self.image)

221

222 @property

223 def rect(self):

224 return Rect(self.x,self.y,self.width,self.height)

225 @property

226 def image(self):

227 return self.stone_image

228

229 @property

230 def mask(self):

231 return self.mask_image

232

233 def update(self,frame = 1):

234 self.x -= int(self.speed*frames_to_msec(frame))

235

236 def collides(self, b):

237 return pygame.sprite.collide_mask(self, b)

238

239 def visible(self):

240 return -self.width<self.x<BK_WIDTH

241

242

243 #返回每关需要达到的通关分数

244 def level_goal(bird):

245 return bird.level*BIRD_INIT_SCORE

246

247 #载入图片

248 def load_image(img_file_name):

249 file_name = os.path.join(".","images",img_file_name)#进行路径字符串的合并

250 img = pygame.image.load(file_name)

251 img.convert()

252 return img

253

254 #根据所在的等级返回需要的背景名

255 def search_bk(bird):

256 return "bk"+str(bird.level)

257

258 img_x = load_image('backgroundx.png')#加载背景图像

259 def load_images():

260 #加载所有游戏需要用到的图像

261 #上面写了这个函数下面就用了起来 join用于分隔符和元组的拼接 os.path.join 用于路径的顺序拼接

262 return {'bk1': load_image('background.png'),

263 'bk2':load_image("background2.png"),

264 "bk3":load_image("background3.png"),

265 "bk4":load_image("background4.png"),

266 "bk5":load_image("background5.png"),

267 "bk6":load_image("background6.png"),

268 'stone':load_image('stone.png'),

269 'bullet': load_image('bullet.png'),

270 'pipe-end': load_image('pipe_end.png'),

271 'pipe-body': load_image('pipe_body.png'),

272 'f_u': load_image('fenghuang_up.png'),

273 'f_m': load_image('fenghuang_mid.png'),

274 'f_w': load_image('fenghuang_down.png'),

275 'bird-wingup': load_image('bird_wing_up.png'),

276 'bird-wingmid': load_image('bird_wing_mid.png'),

277 'bird-wingdown': load_image('bird_wing_down.png')}

278

279 def frames_to_msec(frames,fps=FPS):

280 return 1000.0*frames/fps #难道限制的意思就是我可以限制图片出来的时间

281

282 def msec_to_frames(milliseconds, fps=FPS):

283 return fps * milliseconds / 1000.0#转化成对应的帧数

284 #转化成每秒的相应的帧数

285

286

287 def game_loop():

288 pygame.mixer.music.play(-1)

289 pygame.display.set_caption("Flappy Bird")

290 clock = pygame.time.Clock()#创建一个时钟对象

291 images = load_images()#建立所有需要的图像字典

292

293 bird = Bird(20,BK_HEIGHT//2,1,(images[a_i],images[b_i] ,images[c_i]))

294 score_font = pygame.font.SysFont(None,50,bold=True)#名字 大小 粗体 建立画笔 用于记录 分数

295 score_font2 = pygame.font.SysFont(None, 40, bold=True) # 名字 大小 粗体 建立画笔 用于记录 分数

296 score_font3 = pygame.font.SysFont(None, 70, bold=True) # 名字 大小 粗体 建立画笔 用于记录 分数

297 pipes = deque()

298

299 stones =pygame.sprite.Group()#将石头新建为一个精灵组

300 bullets =pygame.sprite.Group()#将子弹新建为一个精灵组

301

302 pause = done = False

303 frames=0

304

305 while not done :#当没有按下中止键

306 clock.tick(FPS)

307 if not (pause or frames%msec_to_frames(Pipe.add_time)):#如果没有按下暂停 或者满足新生成柱子的条件

308 pp=Pipe(images['pipe-end'], images['pipe-body'])

309 pipes.append(pp)#生成新管子 并加入队列

310

311 if not (pause or frames%msec_to_frames(Stone.add_time)or bird.level<STONE_LEVEL):

312 ss = Stone(images["stone"])

313 stones.add(ss) #加入新生成的石头

314

315 #判断发生了什么事件进行相应的处理

316 for e in pygame.event.get():

317 if e.type == QUIT:

318 done = True

319 break

320 elif e.type == KEYUP :

321 if e.key == K_p:

322 pause = not pause

323 elif e.key ==K_d:#发射子弹

324 bb=Bullet(bird,images["bullet"])

325 bullets.add(bb)

326 elif e.key ==K_s or e.key == K_SPACE:

327 bird.inital_speed = INITAL_SPEED

328

329

330 elif e.type == MOUSEBUTTONUP:

331 bird.inital_speed =INITAL_SPEED

332

333 # 重新更新时间

334 # 使小鸟又进入相应的运动的开始

335 if pause:

336 continue # 这个时段什么都不做

337

338 pygame.sprite.groupcollide(stones,bullets,True,True,pygame.sprite.collide_mask)

339 pipe_collision = any(p.collides(bird) for p in pipes)

340 stone_collision = any(s.collides(bird) for s in stones)

341

342 if pipe_collision:

343 pygame.mixer.music.stop()

344 done = True

345 pygame.mixer.Sound.play(music_lose, -1)

346 time.sleep(3.5)

347 pygame.mixer.Sound.stop(music_lose)

348 time.sleep(0.1)

349

350 if stone_collision:

351 pygame.mixer.music.stop()

352 pygame.mixer.Sound.play(music_lose, -1)

353 time.sleep(3.5)

354 pygame.mixer.Sound.stop(music_lose)

355 time.sleep(0.1)

356 done = True

357 if 0>=bird.y or bird.y>BK_HEIGHT-Bird.height:

358 done = True

359 pygame.mixer.music.stop()

360 pygame.mixer.Sound.play(music_lose, -1)

361 time.sleep(3.5)

362 pygame.mixer.Sound.stop(music_lose)

363 time.sleep(0.1)

364

365

366 screen.blit(images[search_bk(bird)], (0, 0))#画背景墙 这种是分开两张的

367

368 while pipes and not pipes[0].visible:

369 pipes.popleft()#当队列不为空 且管子 0 已经不可见的时候

370 for s in stones:#删除看不见的石头

371 if not s.visible():

372 del s

373 for b in bullets:#删除看不见的子弹

374 if not b.visible():

375 del b

376

377

378 for p in pipes:

379 p.update()

380 screen.blit(p.image,p.rect)#在指定的位置 画柱子

381 for s in stones:

382 s.update()

383 screen.blit(s.image,s.rect)

384

385 for b in bullets:

386 b.update()

387 screen.blit(b.bullet,b.rect)

388

389 for p in pipes:

390 if bird.x>p.x+Pipe.width and not p.score_count: #当柱子超过了鸟的位置并且柱子还没有被计分

391 bird.score+=1

392 p.score_count = True

393

394 sl = score_font.render("level:",True,(255,255,255))

395 sc = score_font.render("score:",True,(255,255,255))

396 sl2 = score_font2.render(str(bird.level),True,(255,255,255))

397 sc2 = score_font2.render(str(bird.score),True,(255,255,255))

398 screen.blit (sc,(BK_WIDTH-170,20))

399 screen.blit(sl, (BK_WIDTH - 320, 20))

400 screen.blit(sc2, (BK_WIDTH - 50, 27))

401 screen.blit(sl2, (BK_WIDTH - 210, 27))

402

403 bird.update(frames_to_msec(1))#计算一帧所需要的时间

404 screen.blit(bird.image,bird.rect)

405

406 pygame.display.flip()#绘制图像到屏幕

407 if bird.score >= level_goal(bird):#如果已经达到了通关分数

408 #升入下一级 首先要初始化所有变量#清空柱子#改变等级

409 change_add_time()

410 pipes.clear()

411 stones.empty()

412 bullets.empty()

413 bird.level += 1 # 分数先暂不做清空后续再加入吧

414 if bird.level<=6:

415 s3 = score_font3.render("Next Level", True, (255, 255, 255))

416 screen.blit(s3, (BK_WIDTH//2-150, BK_HEIGHT//2-50))

417 pygame.display.flip()

418 time.sleep(2)

419 if bird.level >6:

420 s3 = score_font3.render("You Win!", True, (255, 255, 255))

421 screen.blit(s3, (BK_WIDTH // 2 - 150, BK_HEIGHT // 2 - 50))

422 pygame.display.flip()

423 time.sleep(2)

424 exit()

425 frames+= 1

426 pygame.mixer.music.stop()

427

428 Pipe.add_time = ADD_TIME#再次初始化柱子的速度

429 main()

430

431

432 def quit_but():

433 pygame.quit()

434 exit()

435

436

437 def buttons(x, y, w, h, color, color2, text,action,list=[]):

438 mouse_position = pygame.mouse.get_pos()

439 click = pygame.mouse.get_pressed()

440 if x+w > mouse_position[0] > x and y+h > mouse_position[1] > y:

441 color = color2

442 #get_pressed 只返回鼠标三个键是否被按过的状态 不会分辨它是在哪里被按的

443 if click[0]== 1 and action != None:

444 pygame.mixer.Sound.play(music1, -1)

445 time.sleep(0.215)

446 pygame.mixer.Sound.stop(music1)

447 if list:

448 action(list)

449 else:

450 action()

451

452 pygame.draw.rect(screen, color, (x, y, w, h))

453 # font = pygame.font.SysFont('comicsansms', 25)

454 TextSurf = font.render(text, True, (0,0,0))

455 TextRect = TextSurf.get_rect()

456 TextRect.center = ((x + (w / 2)), (y + (h / 2)))

457 screen.blit(TextSurf, TextRect)

458 pygame.display.update()

459

460

461 def setting():

462 # img = load_image('backgroundx.png')

463 screen.blit(img_x, (0, 0)) # 画背景墙 这种是分开两张的

464 pygame.display.flip()

465 while True:

466 for event in pygame.event.get():

467 if event.type==pygame.QUIT:

468 exit()

469

470 buttons(100, 200, BUTTON_WIDTH, BUTT0N_HEIGHT,(255, 0, 0), (170, 0, 0), 'easy',seteasy,[0.19,2500,int(5 / 11 * BK_HEIGHT),0.97,5,6]) # 绘制图标 进行事件

471 buttons(400, 200, BUTTON_WIDTH, BUTT0N_HEIGHT,(0, 255, 0), (0, 170, 0), 'normal', seteasy,[0.19,2500,int(3 / 5 * BK_HEIGHT),0.96,7,4]) # 绘制图标 进行事件

472 buttons(700 ,200, BUTTON_WIDTH, BUTT0N_HEIGHT,(0, 0, 255), (0, 0, 160),'hard',seteasy,[0.21,1300,int(9 / 14 * BK_HEIGHT),0.96,2,1]) # 绘制图标 进行事件

473 buttons(700, 550, BUTTON_WIDTH, BUTT0N_HEIGHT, (0, 0, 255), (0, 0, 160), 'back', main) # 绘制图标 进行事件

474 buttons(100, 400, BUTTON_WIDTH, BUTT0N_HEIGHT, (255, 0, 0), (170, 0, 0), 'huo lie niao',little_bird,["f_u","f_m","f_w"]) # 绘制图标 进行事件

475 buttons(400, 400, BUTTON_WIDTH, BUTT0N_HEIGHT, (0, 255, 0), (0, 170, 0), 'xiao niao',little_bird,["bird-wingup","bird-wingmid","bird-wingdown"]) # 绘制图标 进行事件

476 # buttons(700, 400, BUTTON_WIDTH, BUTT0N_HEIGHT, (0, 0, 255), (0, 0, 160), 'back', main) # 绘制图标 进行事件

477

478

479 def main():

480 screen.blit(img_x, (0, 0)) # 画背景墙 这种是分开两张的

481 pygame.display.flip()

482 while True:

483 for event in pygame.event.get():

484 if event.type==pygame.QUIT:

485 exit()

486 buttons((BK_WIDTH-BUTTON_WIDTH)//2,(BK_HEIGHT-BUTT0N_HEIGHT-100)//2,BUTTON_WIDTH,BUTT0N_HEIGHT,(0,255,0),(0,170,0),'Play!',game_loop)#绘制图标 进行事件

487 buttons((BK_WIDTH - BUTTON_WIDTH) // 2, (BK_HEIGHT - BUTT0N_HEIGHT + 100) // 2, BUTTON_WIDTH, BUTT0N_HEIGHT,(0, 0, 255), (0, 0, 160), 'setting', setting) # 绘制图标 进行事件

488 buttons((BK_WIDTH - BUTTON_WIDTH) // 2, (BK_HEIGHT - BUTT0N_HEIGHT + 300) // 2, BUTTON_WIDTH, BUTT0N_HEIGHT,(255, 0, 0), (170, 0, 0), 'Quit', quit_but)

489

490 if __name__ =="__main__":

491 main()

上述代码是第1版本,简单起见 没有完全封装为面向对象,等后面有时间再进行完善 目标是:全部用类进行分装,然后拆分到多个模块中

以上是 Python3 pygame实现flappy bird游戏 的全部内容, 来源链接: utcz.com/a/121617.html

回到顶部