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

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

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

一、运行效果展示

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

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

image

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

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

二、完整代码

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

import math
import os
import time
from  random import randint
from random import uniform
import pygame
from pygame.locals import * #导入一些常用的变量
from collections import deque#加入了队列

FPS = 60
BK_WIDTH = 900  #背景宽度
BK_HEIGHT = 650  #背景高度
PIPE_WIDTH = 80 #水管的宽度
PIPE_HEIGHT = 10 #水管素材的高度
PIPE_HEAD_HEIGHT = 32#管子头的高度

#初始化全局变量
BK_MOVE_SPEED = 0.22#主柱子每毫秒移动的速度
ADD_TIME = 2500##每隔多少毫秒就增加一个柱子 这种方法不会有漏洞吗  就是当毫秒数和帧数不匹配啥的  #还需要仔细的思考
TOTAL_PIPE_BODY  =  int(3/5 * BK_HEIGHT)  # 像素值必须为整数   占窗口的3/5
PIPE_RATE =0.96
a_i="bird-wingup"
b_i="bird-wingmid"
c_i="bird-wingdown"

INITAL_SPEED = -0.37#鸟的Y轴初速度
BIRD_WIDTH = 50
BIRD_HEIGHT = 40
BIRD_INIT_SCORE  = 7#鸟的初始通关分数

STONE_ADD_TIME = 1000 #每隔多少毫秒就增加一个石头
STONE_WIDTH = 40
STONE_HEIGHT = 30
STONE_LEVEL = 4#石头出现的等级

BUTTON_WIDTH = 140
BUTT0N_HEIGHT = 60

BULLET_SPEED = 0.32#子弹的速度
BULLET_WIETH = 50
BULLET_HEIGHT = 30
#设置全局变量 方便修改参数


pygame.init()
screen = pygame.display.set_mode((BK_WIDTH,BK_HEIGHT))
pygame.mixer.init()

music_lose = pygame.mixer.Sound("lose.wav")
music1 = pygame.mixer.Sound("touch.wav")
pygame.mixer.music.load("bkm.mp3")
font = pygame.font.SysFont('comicsansms', 25)


#用于设置鸟的种类
def little_bird(list):
    global a_i
    global b_i
    global c_i
    a_i=list[0]
    b_i=list[1]
    c_i=list[2]


#用于设置关卡难度
def seteasy(list):
    global BK_MOVE_SPEED  # 背景每毫秒移动的速度   就是柱子移动的速度
    global ADD_TIME  # 每隔多少毫秒就增加一个柱子
    global TOTAL_PIPE_BODY  # 像素值必须为整数   占窗口的3/5
    global PIPE_RATE
    global STONE_LEVEL  # 鸟出现的等
    global BIRD_INIT_SCORE

    BK_MOVE_SPEED = list[0]  # 背景每毫秒移动的速度
    ADD_TIME = list[1]  # 每隔多少毫秒就增加一个柱子
    TOTAL_PIPE_BODY =list[2]  # 像素值必须为整数   占窗口的3/5
    PIPE_RATE = list[3]
    Pipe.add_time = list[1]
    BIRD_INIT_SCORE = list[4]
    STONE_LEVEL = list[5]


#子弹类
class Bullet(pygame.sprite.Sprite):
    speed = BULLET_SPEED
    width = BULLET_WIETH
    height = BULLET_HEIGHT

    def __init__(self,bird,images):
        super(Bullet,self).__init__() #d调用父类的初始函数 使用此方法 可以减少代码的更改量 并且解决了多重继承的问题
        self.x,self.y = bird.x,bird.y
        self.bullet = images #给鸟的图片进行赋值
        self.mask_bullet = pygame.mask.from_surface(self.bullet)
    def update(self):#计算鸟在下一点的新坐标并更新
        self.x=self.x+self.speed*frames_to_msec(1)
    @property
    def image(self):
        return self.bullet
    @property
    def mask(self):
        return self.mask_bullet
    @property
    def rect(self):
        return Rect(self.x,self.y,Bullet.width,Bullet.height)
    def visible(self):
        return 0=120:
            return self.wing_up
        elif pygame.time.get_ticks()%400>=280:
            return self.wing_mid
        else:
            return self.wing_down
    @property
    def mask(self):
        if pygame.time.get_ticks()%400>=120:
            return self.mask_wing_up
        elif pygame.time.get_ticks()%400>=280:
            return self.mask_wing_mid
        else:
            return self.mask_wing_down

    @property
    def rect(self):
        return Rect(self.x,self.y,Bird.width,Bird.height)



class Pipe(pygame.sprite.Sprite):
    width = PIPE_WIDTH
    pipe_head_height = PIPE_HEAD_HEIGHT
    add_time = ADD_TIME

    def __init__(self,pipe_head_image,pipe_body_image):
        super(Pipe, self).__init__()
        self.x = float(BK_WIDTH-1)
        self.score_count = False
        self.image = pygame.Surface((Pipe.width,BK_HEIGHT),SRCALPHA)#创建一个surface 我理解为能画到窗口上的对象
        # #意为创建一个有ALPHA 通道的surface 如果需要透明就需要这个选项
        self.image.convert()
        self.image.fill((0,0,0,0))#前三位是颜色  最后一位是透明度
        total_pipe_length = TOTAL_PIPE_BODY

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

        for i in range(1,self.bottom_length+1):
            pos = (0,BK_HEIGHT - i)
            self.image.blit (pipe_body_image,pos)#用重叠的技术画出来管子

        bottom_head_y = BK_HEIGHT - self.bottom_length-self.pipe_head_height  #求出管子头的长度
        bottom_head_pos = (0,bottom_head_y)
        self.image.blit(pipe_head_image,bottom_head_pos)#画管子

        for i in range(-PIPE_HEIGHT,self.top_length-PIPE_HEIGHT):
            pos = (0,i)
            self.image.blit(pipe_body_image,pos)
        top_head_y = self.top_length
        self.image.blit(pipe_head_image,(0,top_head_y))

        self.mask = pygame.mask.from_surface(self.image)
    @property
    def rect(self):
        return Rect(self.x,0,Pipe.width,PIPE_HEIGHT)
    @property
    def visible(self):
        return -Pipe.width=bird.y or bird.y>BK_HEIGHT-Bird.height:
            done = True
            pygame.mixer.music.stop()
            pygame.mixer.Sound.play(music_lose, -1)
            time.sleep(3.5)
            pygame.mixer.Sound.stop(music_lose)
            time.sleep(0.1)


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

        while pipes and not pipes[0].visible:
            pipes.popleft()#当队列不为空  且管子 0 已经不可见的时候
        for s in stones:#删除看不见的石头
            if  not s.visible():
                del s
        for b in bullets:#删除看不见的子弹
            if not b.visible():
                del b


        for p in pipes:
            p.update()
            screen.blit(p.image,p.rect)#在指定的位置 画柱子
        for s in stones:
            s.update()
            screen.blit(s.image,s.rect)

        for b in bullets:
            b.update()
            screen.blit(b.bullet,b.rect)

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

        sl = score_font.render("level:",True,(255,255,255))
        sc = score_font.render("score:",True,(255,255,255))
        sl2 = score_font2.render(str(bird.level),True,(255,255,255))
        sc2 = score_font2.render(str(bird.score),True,(255,255,255))
        screen.blit (sc,(BK_WIDTH-170,20))
        screen.blit(sl, (BK_WIDTH - 320, 20))
        screen.blit(sc2, (BK_WIDTH - 50, 27))
        screen.blit(sl2, (BK_WIDTH - 210, 27))

        bird.update(frames_to_msec(1))#计算一帧所需要的时间
        screen.blit(bird.image,bird.rect)

        pygame.display.flip()#绘制图像到屏幕
        if bird.score >= level_goal(bird):#如果已经达到了通关分数
        #升入下一级  首先要初始化所有变量#清空柱子#改变等级
            change_add_time()
            pipes.clear()
            stones.empty()
            bullets.empty()
            bird.level += 1  # 分数先暂不做清空后续再加入吧
            if bird.level<=6:
                s3 = score_font3.render("Next   Level", True, (255, 255, 255))
                screen.blit(s3, (BK_WIDTH//2-150, BK_HEIGHT//2-50))
                pygame.display.flip()
                time.sleep(2)
            if bird.level >6:
                s3 = score_font3.render("You   Win!", True, (255, 255, 255))
                screen.blit(s3, (BK_WIDTH // 2 - 150, BK_HEIGHT // 2 - 50))
                pygame.display.flip()
                time.sleep(2)
                exit()
        frames+= 1
    pygame.mixer.music.stop()

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


def quit_but():
    pygame.quit()
    exit()


def buttons(x, y, w, h, color, color2, text,action,list=[]):
    mouse_position = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed()
    if x+w > mouse_position[0] > x and y+h > mouse_position[1] > y:
        color = color2
        #get_pressed  只返回鼠标三个键是否被按过的状态 不会分辨它是在哪里被按的
        if click[0]== 1 and action != None:
            pygame.mixer.Sound.play(music1, -1)
            time.sleep(0.215)
            pygame.mixer.Sound.stop(music1)
            if list:
                action(list)
            else:
                action()

    pygame.draw.rect(screen, color, (x, y, w, h))
    # font = pygame.font.SysFont('comicsansms', 25)
    TextSurf = font.render(text, True, (0,0,0))
    TextRect = TextSurf.get_rect()
    TextRect.center = ((x + (w / 2)), (y + (h / 2)))
    screen.blit(TextSurf, TextRect)
    pygame.display.update()


def setting():
    # img = load_image('backgroundx.png')
    screen.blit(img_x, (0, 0))  # 画背景墙 这种是分开两张的
    pygame.display.flip()
    while True:
        for event in pygame.event.get():
            if event.type==pygame.QUIT:
                exit()

        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])  # 绘制图标  进行事件
        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])  # 绘制图标  进行事件
        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])  # 绘制图标  进行事件
        buttons(700, 550, BUTTON_WIDTH, BUTT0N_HEIGHT, (0, 0, 255), (0, 0, 160), 'back', main)  # 绘制图标  进行事件
        buttons(100, 400, BUTTON_WIDTH, BUTT0N_HEIGHT, (255, 0, 0), (170, 0, 0), 'huo lie niao',little_bird,["f_u","f_m","f_w"])  # 绘制图标  进行事件
        buttons(400, 400, BUTTON_WIDTH, BUTT0N_HEIGHT, (0, 255, 0), (0, 170, 0),  'xiao niao',little_bird,["bird-wingup","bird-wingmid","bird-wingdown"])  # 绘制图标  进行事件
        # buttons(700, 400, BUTTON_WIDTH, BUTT0N_HEIGHT, (0, 0, 255), (0, 0, 160), 'back', main)  # 绘制图标  进行事件


def main():
    screen.blit(img_x, (0, 0))  # 画背景墙 这种是分开两张的
    pygame.display.flip()
    while True:
        for event in pygame.event.get():
            if event.type==pygame.QUIT:
                exit()
        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)#绘制图标  进行事件
        buttons((BK_WIDTH - BUTTON_WIDTH) // 2, (BK_HEIGHT - BUTT0N_HEIGHT + 100) // 2, BUTTON_WIDTH, BUTT0N_HEIGHT,(0, 0, 255), (0, 0, 160), 'setting', setting)  # 绘制图标  进行事件
        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)

if __name__ =="__main__":
   main()

上述代码是第1版本,简单起见 没有完全封装为面向对象,等后面有时间再进行完善

目标是:全部用类进行分装,然后拆分到多个模块中

你可能感兴趣的:(pythonpygame后端)