Python小游戏--------像素小鸟(Fallppybird)

背景

        素小鸟是一款像素风格的游戏,玩家需要操控小鸟在绿色水管间穿梭,避免碰撞,玩家需要控制像素鸟去越过各种障碍,不能让小鸟落地,否则就需要重新开始游戏。游戏延续了经典的玩法,非常虐心,越玩越容易上瘾。

运行截图

运行时

代码实现

先导入pygame模块,初始化pygame

import pygame
import random
import time
import os
pygame.init()

初始化游戏窗口,设置游戏窗口大小和标题 ,背景音乐,设置刷新帧率

# Constants 常量
W, H = 288, 512
FPS = 30  # 帧率


SCREEN = pygame.display.set_mode((W, H))
pygame.display.set_caption("现象级烧脑")
Clock = pygame.time.Clock()

start_music = pygame.mixer.Sound("空净.mp3")  # (mixer声音混合器)(sound音效)开始的音效

Floor_y = H - IMAGES["land"].get_height()
Bird_x = 80
Bird_y = 100
素材太多一个用于加载文件夹中所有图片的简单方法。它使用了os.listdir来获取文件夹中的所有文件,然后使用os.path.splitext来分离文件名和扩展名,最后使用pygame.image.load来加载每个图片。
# 素材
IMAGES = {}
for image in os.listdir("image"):  # 加载文件夹
    name, extension = os.path.splitext(image)  # 名值分离
    path = os.path.join("image", image)
    IMAGES[name] = pygame.image.load(path)

 设置一个主函数min用来初始化游戏界面,为了更好的游戏体验采用提供了多个背景,小鸟,水管,并随机选择,

def main():
    while True:
        start_music.play()
        IMAGES["bg_pic"] = IMAGES[random.choice(["bg_day", "bg_night"])]  # 随机背景 随机的键作为big_pic的值
        color = random.choice(["bird_blue", "bird_yellow"])
        IMAGES["birds"] = [IMAGES[color + "_up"], IMAGES[color + "_mid"], IMAGES[color + "_down"]]  # 随机小鸟状态和颜色
        IMAGES["pips_down"] = IMAGES[random.choice(["green_pipe_down", "red_pipe_down"])]
        IMAGES["pips_up"] = IMAGES[random.choice(["green_pipe_up", "red_pipe_up"])]
        menu_window()  # 菜单
        result = game_window()  # 游戏
        end_window(result)  # 结束

 设置一个menu_window函数供了一个简单的界面,地板会持续向左移动,并在到达屏幕左侧边界时重置到右侧循环往复以达到一个简单的动画效果。使用常量 FPS 来控制帧率它可以帮助控制游戏的流畅度和性能

def menu_window():
    # 地板移动
    floor_gap = IMAGES["land"].get_width() - W  # 这个值表示地板可以移动的最大距离,即地板超出屏幕范围的宽度。
    floor_x = 0
    title_x = (W - IMAGES["title"].get_width()) / 2
    title_y = 50
    ready_x = (W - IMAGES["text_ready"].get_width()) / 2
    ready_y = 150
    tutorial_x = (W - IMAGES["tutorial"].get_width()) / 2
    tutorial_y = 220
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_q:
                    return  # 按下空格将返回
        floor_x -= 4  # 向左移动地板。
        if floor_x <= -floor_gap:
            floor_x = 0  # 果 floor_x 小于或等于 -floor_gap,说明地板已经移动到了超出屏幕范围的位置。
            # 在这种情况下,将 floor_x 重置为0,即将地板回到起始位置。
        SCREEN.blit(IMAGES["bg_pic"], (0, 0))
        SCREEN.blit(IMAGES["land"], (floor_x, Floor_y))
        SCREEN.blit(IMAGES["title"], (title_x, title_y))
        SCREEN.blit(IMAGES["text_ready"], (ready_x, ready_y))
        SCREEN.blit(IMAGES["tutorial"], (tutorial_x, tutorial_y))
        pygame.display.update()
        Clock.tick(FPS)

设置show_score函数用来在屏幕上显示分数,它首先将分数转换为字符串,然后根据这个字符串的长度计算每个数字的位置。接着,它遍历这个字符串,将每个数字对应的图片绘制到屏幕上

def show_score(score):

    score_str = str(score)
    n = len(score_str)
    w = IMAGES["0"].get_width() * 1.1
    x = (W - n * w) / 2
    y = H * 0.1
    for number in score_str:
        SCREEN.blit(IMAGES[number], (x, y))
        x += w

 结束界面pygame来创建一个游戏窗口,并在游戏结束时播放特定的画面按下q 重新开始


def end_window(result):
    # 地板移动
    bird = result["bird"]
    # score = result["score"]
    pipe_group = result["pipe_group"]
    floor_gap = IMAGES["land"].get_width() - W
    floor_x = 0
    over_x = (W - IMAGES["text_game_over"].get_width()) / 2
    over_y = (H - IMAGES["text_game_over"].get_height()) / 2

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            if event.type == pygame.KEYDOWN and event.key == pygame.K_q:
                return

        bird.go_die()  # 播放小鸟碰到天花板的画面
        floor_x -= 4
        if floor_x <= -floor_gap:
            floor_x = 0  # 如果地板的宽度小于 地板-屏幕的宽度让地板回到起始位置
        SCREEN.blit(IMAGES["bg_pic"], (0, 0))  # 背景最先画
        pipe_group.draw(SCREEN)  # 水管
        show_score(result["score"])
        SCREEN.blit(IMAGES["text_game_over"], (over_x, over_y))
        SCREEN.blit(IMAGES["land"], (floor_x, Floor_y))
        SCREEN.blit(bird.image, bird.rect)  # 小鸟
        pygame.display.update()
        Clock.tick(FPS)

定义了一个鸟类用来设设定鸟的一些属性值设置了初始的速度,方向,角度,

class Bird:
    def __init__(self, x, y):
        self.idx = 0  # 帧索引
        self.repeat = 5  # 帧循环次数
        self.frames = [0] * self.repeat + [1] * self.repeat + [2] * self.repeat + [1] * self.repeat
        # 这个列表实际上代表了动画的帧数
        # # 其中0、1和2分别代表小鸟的不同姿态(例如,0可能代表小鸟的休息帧,1和2可能代表小鸟拍动翅膀的帧
        self.images = IMAGES["birds"]  # 小鸟图像
        self.image = self.images[self.frames[self.idx]]  # 用列表的索引的序号取得帧对应的序号 最后取得对应的帧
        # 定义小鸟初始化坐标
        self.rect = self.image.get_rect()  # get_rect()方法的作用将图片以位置的形式告诉我们
        self.rect.x = x
        self.rect.y = y
        self.y_val = -8  # 小鸟上升的速度
        self.max_y_val = 10  # y方向的最大速度
        self.gravity = 1  # 重力加速度
        self.rotate = 45  # 小鸟的初始方向
        self.max_rotate = -45  # 旋转最大最大角度
        self.rotate_val = -3  # 旋转速度
        self.y_val_after_flap = -10  # 拍动翅膀后的速度
        self.rotate_after_flap = 45  # 拍动翅膀后的角度

定义了一个update函数用来用来更新一个小鸟对象的属性,包括它的y坐标、旋转角度以及图像。然后你使用pygame的rotate函数来旋转小鸟的图像。

    def update(self, flap=False):  # 跟新小鸟帧与帧之间的关系
        if flap:  # 如果小鸟拍动翅膀重置速度方向
            self.y_val = self.y_val_after_flap
            self.rotate = self.rotate_after_flap

        self.y_val = min(self.y_val + self.gravity, self.max_y_val)  # min函数取两者之间最小值 v=v0+gt
        self.rect.y += self.y_val  # 小鸟飞到最高点 向下掉落
        self.rotate = max(self.rotate + self.rotate_val, self.max_rotate)
        self.idx += 1
        self.idx %= len(self.frames)
        self.image = self.images[self.frames[self.idx]]
        # idx += 排序  # idx每次循环都会增加1
        # idx %= len(frames)  # idx保持在0到len(frames)-1的范围内,这样就可以确保循环不会超出帧数范围。
        self.image = pygame.transform.rotate(self.image, self.rotate)  # 用pygame中的旋转方法给小鸟的帧造型做出旋转效果

定义了一个go_ie函数用来实现鸟死亡后做自由落体的动作

  def go_die(self):  # 碰到天画板以最大的下落速度和角度网下落
        # pass
        if self.rect.y < Floor_y:  # 判断小鸟是否还在地面之上是的话 以垂直的角度自由落体
            self.rect.y += self.max_y_val
            self.rotate = -90
            self.image = self.images[self.frames[self.idx]]
            self.image = pygame.transform.rotate(self.image, self.rotate)

定义了一个水管类来实现水管在屏幕上的生成,水管的生成分上下两部分,

class Pipe(pygame.sprite.Sprite):  # 使用水管继承精灵类
    def __init__(self, x, y, upwards=True):
        pygame.sprite.Sprite.__init__(self)

        if upwards:
            self.image = IMAGES["pips_up"]
            self.rect = self.image.get_rect()
            self.rect.x = x
            self.rect.y = y
            self.x_val = -4
        else:
            self.image = IMAGES["pips_down"]
            self.rect = self.image.get_rect()
            self.rect.x = x
            self.rect.bottom = y
            self.x_val = -4

 用来跟新地面的移动

    def update(self):
        self.rect.x += self.x_val

 游戏运行窗口的实现,在屏幕上绘制得分,用精灵组实现水管的生成

(解释一下什么是精灵组是一个包含多个精灵的对象。在创建精灵组的时候可以使用多值参数的方式,一次性把精灵组中包含的所有精灵传入到精灵组内部。当有了精灵组之后,在编写游戏循环代码时,只需要在游戏循环中,让精灵组调用两个方法:update方法和draw方法。当让精灵组调用update方法时,精灵组就会让组中所有的精灵各自调用各自的update方法,根据游戏的需求,各自修改各自不同的位置。当所有的精灵更新完位置之后,再让精灵组调一下draw方法,同时把屏幕对象当作参数传递给draw方法,draw方法会把精灵组中所有精灵的image绘制到屏幕上每一个精灵对应的rect位置),

def game_window():
    score = 0  # 得分
    distance = 150  # 水管间隔
    n = 3  # 水管个数
    pipe_gap = 150  # 上下水管间距
    # 开启精灵组替代列表
    pipe_group = pygame.sprite.Group()
    for i in range(n):
        pipe_y = random.randint(int(H * 0.4), int(H * 0.6))
        pipe_up = Pipe(W + i * distance, pipe_y, True)
        pipe_down = Pipe(W + i * distance, pipe_y - pipe_gap, False)
        pipe_group.add(pipe_up)
        pipe_group.add(pipe_down)

    floor_gap = IMAGES["land"].get_width() - W
    floor_x = 0
    bird = Bird(80, 180)

    while True:
        flap = False
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    flap = True

        floor_x -= 4
        if floor_x <= -floor_gap:
            floor_x = 0  # 如果地板的宽度小于 地板-屏幕的宽度让地板回到起始位置
        # idx += 排序

        # idx %= len(frames
        bird.update(flap)
        first_pipe_up = pipe_group.sprites()[0]
        first_pipe_down = pipe_group.sprites()[1]

        if first_pipe_up.rect.right < 0:  # 如果水管移除画面销毁,并新建水管

            pipe_y = random.randint(int(H * 0.4), int(H * 0.6))
            new_pipe_up = Pipe(first_pipe_up.rect.x + n * distance, pipe_y, True)
            new_pipe_down = Pipe(first_pipe_up.rect.x + n * distance, pipe_y - pipe_gap, False)
            pipe_group.add(new_pipe_up)
            pipe_group.add(new_pipe_down)
            first_pipe_down.kill()
            first_pipe_up.kill()  # 使用精灵里kill方法自行销毁

        pipe_group.update()  # 跟新精灵组

        if bird.rect.y > Floor_y or bird.rect.y < 0 or pygame.sprite.spritecollideany(bird, pipe_group):
            # 利用精灵组中的spritecollideany方法自动判断 小鸟和水管碰撞
            result = {"bird": bird, "pipe_group": pipe_group, "score": score}
            return result
        if bird.rect.left + first_pipe_up.x_val < first_pipe_up.rect.centerx < bird.rect.left:
            score += 1
        SCREEN.blit(IMAGES["bg_pic"], (0, 0))
        pipe_group.draw(SCREEN)  # 告诉精灵组画在哪个屏幕上
        show_score(score)
        SCREEN.blit(IMAGES["land"], (floor_x, Floor_y))
        SCREEN.blit(bird.image, bird.rect)
        pygame.display.update()
        Clock.tick(FPS)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值