前文
相信大家肯定玩过或见过这个游戏,我之前也一直在手机上玩flappy bird游戏,闲暇时间就编写了一个
是采用python3+pygame模块制作而成的,运行效果非常流畅,会让你大吃一惊哦!^_^
一、运行效果展示
下载游戏之后,注意在自己的python环境中安装pygame模块,如果没有安装可以使用pip install pygame 进行安装
然后使用使用命令运行起这个.py文件,运行之后的第一个界面效果如下,是不是很酷炫
当点击上图中的“Play”按钮之后的效果如下:
运行之后是有音乐的,大家可以下载代码的时候一起将素材下载,这样就在运行时就能听到音乐
二、完整代码
下面代码用到了素材(背景图片,音乐等,下载地址:https://docs.qq.com/doc/DYUhqVEJ0d013alVC)
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 @property100 def mask(self):101 return self.mask_bullet102 @property103 def rect(self):104 return Rect(self.x,self.y,Bullet.width,Bullet.height)105 def visible(self):106 return 0=120:136 return self.wing_up137 elif pygame.time.get_ticks()%400>=280:138 return self.wing_mid139 else:140 return self.wing_down141 @property142 def mask(self):143 if pygame.time.get_ticks()%400>=120:144 return self.mask_wing_up145 elif pygame.time.get_ticks()%400>=280:146 return self.mask_wing_mid147 else:148 return self.mask_wing_down149 150 @property151 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_WIDTH158 pipe_head_height = PIPE_HEAD_HEIGHT159 add_time = ADD_TIME160 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 = False165 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_BODY170 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_length173 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_length186 self.image.blit(pipe_head_image,(0,top_head_y))187 188 self.mask = pygame.mask.from_surface(self.image)189 @property190 def rect(self):191 return Rect(self.x,0,Pipe.width,PIPE_HEIGHT)192 @property193 def visible(self):194 return -Pipe.width=bird.y or bird.y>BK_HEIGHT-Bird.height:358 dOne= True359 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 s373 for b in bullets:#删除看不见的子弹374 if not b.visible():375 del b376 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+=1392 p.score_count = True 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+= 1426 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 = color2442 #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版本,简单起见 没有完全封装为面向对象,等后面有时间再进行完善 目标是:全部用类进行分装,然后拆分到多个模块中
总结
欢迎大家指出不足,或者你有更好的建议,可以写在评论区一起交流。
最后,有需要这个实例所有文件的可以点击下面的链接:)
https://docs.qq.com/doc/DYUhqVEJ0d013alVC
提示:支持键盘“← →”键翻页