一、初始pygame

1.游戏框架搭建

  • pygame游戏框架搭建大体分为四个步骤,如下图所示:

  • 参考代码:

    # 导入pygame
    import pygame
    
    # 初始化游戏
    pygame.init()
    
    # 游戏代码【这里写我们的游戏代码主体部分,比如游戏窗口,标题,背景颜色等等】
    # 游戏窗口
    screen = pygame.display.set_mode((480, 700))  # 宽:480,高:700
    # 游戏退出
    pygame.quit()
    

    2.添加循环

    以上代码执行后,游戏窗口闪一下就关闭了。我们需要在窗口下方添加一个无限循环,让窗口一直显示。

    # 导入pygame
    import pygame
    
    # 初始化游戏
    pygame.init()
    
    # 游戏代码【这里写我们的游戏代码主体部分,比如游戏窗口,标题,背景颜色等等】
    # 游戏窗口
    screen = pygame.display.set_mode((480, 700))  # 宽:640,高:700
    
    # 添加无限循环,让窗口一直显示
    while True:
        pass
    
    # 游戏退出
    pygame.quit()
    

    3.监听事件

    以上代码执行后,窗口可以一直显示,但无法关闭。所以我们需要监听事件消息,例如关闭窗口事件,按下键盘事件等等。

    # 导入pygame
    import pygame
    
    # 初始化游戏
    pygame.init()
    
    # 游戏代码【这里写我们的游戏代码主体部分,比如游戏窗口,标题,背景颜色等等】
    # 游戏窗口
    screen = pygame.display.set_mode((480, 700))  # 宽:640,高:700
    
    #循环
    while True:
        # 监听所有事件
        for event in pygame.event.get():
            # 点击❌号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
    

    4.最终代码

    基本设置完成后,我们可以设置窗口标题,更改背景颜色等等

    # 导入pygame
    import pygame
    
    # 初始化游戏
    pygame.init()
    
    # 游戏代码【这里写我们的游戏代码主体部分,比如游戏窗口,标题,背景颜色等等】
    # 游戏窗口
    screen = pygame.display.set_mode((480, 700))  # 宽:640,高:700
    # 窗口标题
    pygame.display.set_caption('原神')
    # 自定义颜色
    bg_color1 = (255,0,0)
    # 游戏窗口背景颜色
    screen.fill(bg_color1)
    
    
    #循环
    while True:
        # 监听所有事件
        for event in pygame.event.get():
            # 点击❌号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
    

    以上代码结束后,颜色无法更改,我们需要加一行代码pygame.display.flip,去刷新屏幕。代码如下:

    # 导入pygame
    import pygame
    
    # 初始化游戏
    pygame.init()
    
    # 游戏代码【这里写我们的游戏代码主体部分,比如游戏窗口,标题,背景颜色等等】
    # 游戏窗口
    screen = pygame.display.set_mode((480, 700))  # 宽:640,高:700
    # 窗口标题
    pygame.display.set_caption('原神')
    # 自定义颜色
    bg_color1 = (255,0,0)
    # 游戏窗口背景颜色
    screen.fill(bg_color1)
    
    
    #循环
    while True:
        # 监听所有事件
        for event in pygame.event.get():
            # 点击❌号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
        # 刷新屏幕
    	pygame.display.flip()
    

    二、Pygame进阶

    1.游戏窗口坐标系

    2.画圆

    # 导入pygame
    import pygame
    
    # 初始化游戏
    pygame.init()
    
    # 游戏代码【这里写我们的游戏代码主体部分,比如游戏窗口,标题,背景颜色等等】
    # 游戏窗口
    screen = pygame.display.set_mode((480, 700))  # 宽:640,高:700
    # 窗口标题
    pygame.display.set_caption('原神')
    # 自定义颜色
    bg_color1 = (255,0,0)
    # 游戏窗口背景颜色
    screen.fill(bg_color1)
    # 绘制一个蓝色实心的圆形,其中[60,250]表示圆心的位置,40为半径,width默认为0
    pygame.draw.circle(screen, (0, 0, 255), [60, 250], 40,0)
    
    #循环
    while True:
        # 监听所有事件
        for event in pygame.event.get():
            # 点击❌号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
        # 刷新屏幕
        pygame.display.flip()
    
    

    3.插入图片

    # 导入pygame
    import pygame
    
    # 初始化游戏
    pygame.init()
    
    # 游戏代码【这里写我们的游戏代码主体部分,比如游戏窗口,标题,背景颜色等等】
    # 游戏窗口
    screen = pygame.display.set_mode((480, 700))  # 宽:640,高:700
    # 窗口标题
    pygame.display.set_caption('原神')
    
    ball = pygame.image.load("ball.jpg")  # 加载图片
    WHITE = (255, 255, 255) #白色
    
    
    
    #循环
    while True:
        # 监听所有事件
        for event in pygame.event.get():
            # 点击❌号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
    
        screen.fill(WHITE) #重新背景颜色为白色
        screen.blit(ball,(0,0))# 在原点位置放置图片
        pygame.display.update()# 刷新屏幕
    
    

    4.让图片移动

    # 导入pygame
    import pygame
    import time
    # 初始化游戏
    pygame.init()
    
    # 游戏代码【这里写我们的游戏代码主体部分,比如游戏窗口,标题,背景颜色等等】
    # 游戏窗口
    screen = pygame.display.set_mode((480, 700))  # 宽:640,高:700
    
    ball = pygame.image.load("ball.jpg")  # 加载图片
    RED = (255, 0, 0) # 红色
    
    ballrect = ball.get_rect() #获取矩形的区域
    speed = [5,5] #偏移量
    
    #循环
    while True:
        # 监听所有事件
        for event in pygame.event.get():
            # 点击❌号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
        ballrect = ballrect.move(speed) #让图片移动
        screen.fill(RED)  # 背景颜色为红色
        screen.blit(ball, ballrect)# 将图片画到窗口
        pygame.display.flip()# 刷新屏幕
        time.sleep(0.1) #间接控制图片移动速度,越短越快
    
    

    5.碰撞反弹

    # 导入pygame
    import pygame
    import time
    # 初始化游戏
    pygame.init()
    
    # 游戏代码【这里写我们的游戏代码主体部分,比如游戏窗口,标题,背景颜色等等】
    # 游戏窗口
    screen = pygame.display.set_mode((480, 700))  # 宽:640,高:700
    
    ball = pygame.image.load("ball.jpg")  # 加载图片
    RED = (255, 0, 0) # 红色
    
    ballrect = ball.get_rect() #获取矩形的区域
    speed = [5,5] #偏移量
    
    #循环
    while True:
        # 监听所有事件
        for event in pygame.event.get():
            # 点击❌号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
    
        # 碰到左右边缘反弹
        if ballrect.left < 0 or ballrect.right > 480:
            speed[0] = - speed[0]
        # 碰到上下边缘反弹
        if ballrect.top < 0 or ballrect.bottom > 700:
            speed[1] = - speed[1]
    
        ballrect = ballrect.move(speed) #让图片移动
        screen.fill(RED)  # 背景颜色为红色
        screen.blit(ball, ballrect)# 将图片画到窗口
        pygame.display.flip()# 刷新屏幕
        time.sleep(0.1) #间接控制图片移动速度,越短越快
    
    

    三、Pygame进阶(一)

    1.绘制矩形

    # 导入pygame
    import pygame
    import time
    # 初始化游戏
    pygame.init()
    
    # 游戏代码【这里写我们的游戏代码主体部分,比如游戏窗口,标题,背景颜色等等】
    # 游戏窗口
    screen = pygame.display.set_mode((480, 700))  # 宽:640,高:700
    
    RED = (255, 0, 0) # 红色
    
    #循环
    while True:
        # 监听所有事件
        for event in pygame.event.get():
            # 点击❌号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
    
        pygame.draw.rect(screen,RED,(50,50,150,50),0) #绘制矩形,第三个参数为矩形的范围:(left,top,width,height),最后一个参数,0表示填充矩形
        pygame.draw.rect(screen, RED, (250, 50, 150, 50), 1)
        pygame.draw.rect(screen, RED, (50, 150, 150, 50), 10)
        pygame.display.flip()# 刷新屏幕
    

    2.绘制三角形

    # 导入pygame
    import pygame
    import time
    # 初始化游戏
    pygame.init()
    
    # 游戏代码【这里写我们的游戏代码主体部分,比如游戏窗口,标题,背景颜色等等】
    # 游戏窗口
    screen = pygame.display.set_mode((480, 700))  # 宽:640,高:700
    
    
    BLACK = (0, 0, 0)  # 黑色
    WHITE = (255, 255, 255)  # 白色
    RED = (255, 0, 0)  # 红色
    GREEN = (0, 255, 0)  # 绿色
    BLUE = (0, 0, 255)  # 蓝色
    
    screen.fill(WHITE)  # 填充背景色
    #循环
    while True:
        # 监听所有事件
        for event in pygame.event.get():
            # 点击❌号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
    
        """绘制三角形"""
        points = [(60,0),(0,50),(120,50)]
        pygame.draw.polygon(screen, GREEN, points, 0)
    
        """绘制多边形"""
        points = [(200, 75), (300, 25), (400, 75), (450, 25), (450, 125), (400, 75), (300, 125)]
        pygame.draw.polygon(screen, RED, points, 0)
    
        pygame.display.flip()# 刷新屏幕
    

    3.显示文字

    # 导入pygame
    import pygame
    
    # 初始化游戏
    pygame.init()
    
    # 游戏代码【这里写我们的游戏代码主体部分,比如游戏窗口,标题,背景颜色等等】
    # 游戏窗口
    screen = pygame.display.set_mode((480, 700))  # 宽:640,高:700
    # 窗口标题
    pygame.display.set_caption('原神')
    # 定义颜色
    BLACK = (0, 0, 0)  # 黑色
    WHITE = (255, 255, 255)  # 白色
    RED = (255, 0, 0)  # 红色
    GREEN = (0, 255, 0)  # 绿色
    BLUE = (0, 0, 255)  # 蓝色
    
    #循环
    while True:
        # 监听所有事件
        for event in pygame.event.get():
            # 点击❌号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
    
        text = pygame.font.SysFont("SimHei", 60)  # 创建一个font文本对象
        text_font = text.render("游戏结束", 1, RED, BLUE)  # 渲染文本对象
        screen.blit(text_font, (100,200))  # 绘制文本内容
        pygame.display.update()# 刷新屏幕
    

    3.乒乓球创意

    # 导入pygame
    import pygame
    import time
    # 初始化游戏
    pygame.init()
    
    # 游戏代码【这里写我们的游戏代码主体部分,比如游戏窗口,标题,背景颜色等等】
    # 游戏窗口
    screen = pygame.display.set_mode((600, 550))  # 宽:600,高:550
    # 窗口标题
    pygame.display.set_caption('乒乓球争霸赛')
    
    # 定义颜色
    BLACK = (0, 0, 0)  # 黑色
    WHITE = (255, 255, 255)  # 白色
    RED = (255, 0, 0)  # 红色
    GREEN = (0, 255, 0)  # 绿色
    BLUE = (0, 0, 255)  # 蓝色
    Orange = (225, 121, 21)  # 橙色
    
    x = 120  # 乒乓球的x坐标
    y = 120  # 乒乓球的y坐标
    vx = 1  # 乒乓球的x轴初始速度
    vy = 1  # 乒乓球的y轴初始速度
    
    # boost = 0  # boost是加速器,如果接了10次,那么加速
    score = 0  # score是分数,接到一次乒乓球就加分
    # Bpc= 1  # 基础加分量英文:Basic plus component的缩写
    
    
    # 打印文本
    def printtext(font, text, x, y, color):
        # 渲染文本
        text_font = font.render(text, True, color)
        # 绘制文本
        screen.blit(text_font, (x, y))
    
    #循环
    while True:
        screen.fill(Orange)  # 填充背景为橙色
        # 监听所有事件
        for event in pygame.event.get():
            # 点击❌号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
    
        ### 显示文字 ###
        script1 = pygame.font.SysFont('stkaiti', 24)# 文字:移动鼠标控制乒乓板左右移动
        script2 = pygame.font.SysFont('stkaiti', 20)# 文字:得分
        printtext(script1, "移动鼠标控制乒乓板左右移动", 10, 12, BLACK)
        printtext(script2, "得分", 550, 12, BLACK)
        printtext(script2, str(score), 560, 32, WHITE)
    
    
        ### 乒乓球和球拍 ###
        mx, my = pygame.mouse.get_pos()  # 获得鼠标的x,y坐标
        pygame.draw.circle(screen, BLUE, (x, y), 40, 0)  # 绘制乒乓球
        pygame.draw.rect(screen, GREEN, (mx, 530, 100, 20), 0)  # 绘制球板【鼠标x坐标就是乒乓板的坐标,因此移动鼠标乒乓板也移动】
    
    
        #改变乒乓球的速度
        x = x + vx
        y = y + vy
        # 如果乒乓球碰到左右屏幕边缘,vx取反
        if x > 550 or x < 40:
            vx = -vx
    
        # # 如果碰到上边缘时,vy取反
        if y < 40:
            vy = -vy
    
        # 乒乓球与乒乓板碰撞检测
        if (y + 40 > 530) and (y < 530 + 20) and (x > mx) and (x < mx+100):
            score = score + 1
            # 如果乒乓球是从下往上碰到乒乓板,则反弹
            if vy > 0:
                vy = -vy
    
        # 如果判定没落到球板,则游戏结束,跳出循环
        elif y > 530 and abs(mx - x) > 50:
            print("游戏结束!")
            break
    
        pygame.display.update()# 刷新屏幕
    

    四、滑雪大冒险

    1.第一节课

    # -*-coding:GBK -*-
    # 导入pygame
    import pygame
    # 导入时间库
    import time
    
    # 滑雪者方向不同对应不同的图片
    skier_images = ['./ images/skier_forward.png',
                    "./ images/skier_right1.png",
                    "./ images/skier_right2.png",
                    "./ images/skier_left2.png",
                    "./ images/skier_left1.png"]
    
    # 滑雪者类
    class SkierClass(pygame.sprite.Sprite):
        def __init__(self):
            # 创建一个pygame Sprite类的子类
            pygame.sprite.Sprite.__init__(self)
            # 初始化加载滑雪者向下滑的图片
            self.image = pygame.image.load('./ images/skier_fall.png')
            # 初始化获取图片的矩形大小
            self.rect = self.image.get_rect()
            # 指定滑雪者的中心位置
            self.rect.center = [320, 100]
            # 初始化默认标记滑雪者当前面对的方向(0:代表向下滑)
            self.angle = 0
    
        # 转弯
        def turn(self, direction):
            # 滑雪者当前的移动速度
            self.angle += direction
            # 用于将滑雪者的移动方式固定到这3个方式当中
            if self.angle < -2:
                self.angle = -2
            if self.angle > 2:
                self.angle = 2
            #获取人的位置
            center = self.rect.center
            # 加载滑雪者此时应有的图片
            self.image = pygame.image.load(skier_images[self.angle])
            #初始化图形,注意这里改变了位置
            self.rect = self.image.get_rect()
            #重新定位到人的位置
            self.rect.center = center
    
        # # # 滑雪者左右移动
        def move(self, speed):
            # 更改滑雪者所在的横向位置
            self.rect.centerx += speed
            # 滑雪者所在位置不应该超过的最大最小值
            if self.rect.centerx < 20:
                self.rect.centerx = 20
            if self.rect.centerx > 620:
                self.rect.centerx = 620
    
    # 初始化游戏
    pygame.init()
    # 游戏窗口
    screen = pygame.display.set_mode((640, 640))  # 宽:640,高:640
    # 窗口标题
    pygame.display.set_caption('滑雪大冒险')
    # 创建滑雪者类的实例对象
    skier = SkierClass()
    # 设置移动的x轴距离
    speed = 0
    #设置时钟
    clock = pygame.time.Clock()
    
    #循环
    while True:
        clock.tick(30) #每秒钟执行30次
        # 监听所有事件
        for event in pygame.event.get():
            # 点击?号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
            if event.type == pygame.KEYDOWN:
                # 如果点击左键则向左转
                if event.key == pygame.K_LEFT:
                    skier.turn(-1)
                    speed = -1
                # 如果点击右键则向右转
                elif event.key == pygame.K_RIGHT:
                    skier.turn(1)
                    speed = 1
    
        # 滑雪者移动
        skier.move(speed)
        # 白色背景
        screen.fill([255, 255, 255])
        # 绘制滑雪者
        screen.blit(skier.image,skier.rect)
        # 刷新屏幕
        pygame.display.flip()
    
    

    2.第二节课

    # -*-coding:GBK -*-
    # 导入pygame
    import pygame
    # 导入时间库
    import time
    # 导入随机库
    import random
    
    # 滑雪者方向不同对应不同的图片
    skier_images = ['./ images/skier_forward.png',
                    "./ images/skier_right1.png",
                    "./ images/skier_right2.png",
                    "./ images/skier_left2.png",
                    "./ images/skier_left1.png"]
    
    # 滑雪者类
    class SkierClass(pygame.sprite.Sprite):
        def __init__(self):
            # 创建一个pygame Sprite类的子类
            pygame.sprite.Sprite.__init__(self)
            # 初始化加载滑雪者向下滑的图片
            self.image = pygame.image.load('./ images/skier_fall.png')
            # 初始化获取图片的矩形大小
            self.rect = self.image.get_rect()
            # 指定滑雪者的中心位置
            self.rect.center = [320, 100]
            # 初始化默认标记滑雪者当前面对的方向(0:代表向下滑)
            self.angle = 0
    
        # 转弯
        def turn(self, direction):
            # 滑雪者当前的移动速度
            self.angle += direction
            # 用于将滑雪者的移动方式固定到这3个方式当中
            if self.angle < -2:
                self.angle = -2
            if self.angle > 2:
                self.angle = 2
            #获取人的位置
            center = self.rect.center
            # 加载滑雪者此时应有的图片
            self.image = pygame.image.load(skier_images[self.angle])
            #初始化图形,注意这里改变了位置
            self.rect = self.image.get_rect()
            #重新定位到人的位置
            self.rect.center = center
    
        # # # 滑雪者左右移动
        def move(self, speed):
            # 更改滑雪者所在的横向位置
            self.rect.centerx += speed
            # 滑雪者所在位置不应该超过的最大最小值
            if self.rect.centerx < 20:
                self.rect.centerx = 20
            if self.rect.centerx > 620:
                self.rect.centerx = 620
    
    # 树类
    class TreeClass(pygame.sprite.Sprite):
        def __init__(self, location):
            pygame.sprite.Sprite.__init__(self)
            # 加载树的图片
            self.image = pygame.image.load('./ images/tree.png')
            # 初始化树的位置
            self.location = location
            # 获取图片大小
            self.rect = self.image.get_rect()
            # 指定图片中心位置
            self.rect.center = location
        # 移动
        def update(self):
            global speedy
            self.rect.centery -=speedy
            # 判断树是否移除屏幕
            if self.rect.centery < -32:
                self.kill()
    
    # 旗子类
    class FlagClass(pygame.sprite.Sprite):
        def __init__(self, location):
            pygame.sprite.Sprite.__init__(self)
            # 加载旗子的图片
            self.image = pygame.image.load('./ images/flag.png')
            # 初始化位置
            self.location = location
            # 获取图片大小
            self.rect = self.image.get_rect()
            # 指定图片中心位置
            self.rect.center = location
        # 移动
        def update(self):
            global speedy
            self.rect.centery -=speedy
            # 判断树是否移除屏幕
            if self.rect.centery < -32:
                self.kill()
    
    
    # 创建一个窗口,生成随机的树和小旗
    def create_map():
        global obstacles # 全局变量声明
        locations = []
        for i in range(30):  # 每屏30个障碍物
            row = random.randint(0, 9)  # 获得随机数在 start-end之间
            col = random.randint(0, 9)
            location = [row * 64 + 32, col * 64 + 32 + 640]  # 确定障碍物所在位置(x,y)
            if not (location in locations):  # 确保没有将两个障碍物放在同一个位置
                locations.append(location)
                # 将树添加到游戏
                obstacle_tree = TreeClass(location)
                # 将旗子添加到游戏
                obstacle_flag = FlagClass(location)
                # 将树或者旗子随机放入
                obstacles.add(random.choice([obstacle_tree,obstacle_flag]))
    
    # 初始化游戏
    pygame.init()
    # 游戏窗口
    screen = pygame.display.set_mode((640, 640))  # 宽:640,高:640
    # 窗口标题
    pygame.display.set_caption('滑雪大冒险')
    # 创建滑雪者类的实例对象
    skier = SkierClass()
    # 设置移动的x轴距离
    speed = 0
    #设置时钟
    clock = pygame.time.Clock()
    # 创建独立运动的组织
    obstacles = pygame.sprite.Group()
    # 调用函数,生成树和旗子
    create_map()
    # 设置移动的x轴距离
    speedy = 6
    # 创建一个记录树和旗子移动到哪里的变量
    map_position = 0
    
    
    
    #循环
    while True:
        # time.sleep(0.03)
        map_position += speedy
        if map_position >=640:
            create_map()
            map_position = 0
    
        clock.tick(30) #每秒钟执行30次
        # 监听所有事件
        for event in pygame.event.get():
            # 点击?号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
            if event.type == pygame.KEYDOWN:
                # 如果点击左键则向左转
                if event.key == pygame.K_LEFT:
                    skier.turn(-1)
                    speed = -1
                # 如果点击右键则向右转
                elif event.key == pygame.K_RIGHT:
                    skier.turn(1)
                    speed = 1
    
        # 滑雪者移动
        skier.move(speed)
        # 白色背景
        screen.fill([255, 255, 255])
    
        # 把树和旗子绘制到窗口
        obstacles.draw(screen)
        # 屏幕更新显示
        obstacles.update()
    
        # 绘制滑雪者
        screen.blit(skier.image,skier.rect)
        # 刷新屏幕
        pygame.display.flip()
    
    

    3.第三节课

    # -*-coding:GBK -*-
    # 导入pygame
    import pygame
    # 导入时间库
    import time
    # 导入随机库
    import random
    
    # 滑雪者方向不同对应不同的图片
    skier_images = ['./ images/skier_forward.png',
                    "./ images/skier_right1.png",
                    "./ images/skier_right2.png",
                    "./ images/skier_left2.png",
                    "./ images/skier_left1.png"]
    
    # 滑雪者类
    class SkierClass(pygame.sprite.Sprite):
        def __init__(self):
            # 创建一个pygame Sprite类的子类
            pygame.sprite.Sprite.__init__(self)
            # 初始化加载滑雪者向下滑的图片
            self.image = pygame.image.load('./ images/skier_fall.png')
            # 初始化获取图片的矩形大小
            self.rect = self.image.get_rect()
            # 指定滑雪者的中心位置
            self.rect.center = [320, 100]
            # 初始化默认标记滑雪者当前面对的方向(0:代表向下滑)
            self.angle = 0
    
        # 转弯
        def turn(self, direction):
            # 滑雪者当前的移动速度
            self.angle += direction
            # 用于将滑雪者的移动方式固定到这3个方式当中
            if self.angle < -2:
                self.angle = -2
            if self.angle > 2:
                self.angle = 2
            #获取人的位置
            center = self.rect.center
            # 加载滑雪者此时应有的图片
            self.image = pygame.image.load(skier_images[self.angle])
            #初始化图形,注意这里改变了位置
            self.rect = self.image.get_rect()
            #重新定位到人的位置
            self.rect.center = center
    
        # 滑雪者左右移动
        def move(self, speed):
            # 更改滑雪者所在的横向位置
            self.rect.centerx += speed
            # 滑雪者所在位置不应该超过的最大最小值
            if self.rect.centerx < 20:
                self.rect.centerx = 20
            if self.rect.centerx > 620:
                self.rect.centerx = 620
    
    # 树类
    class TreeClass(pygame.sprite.Sprite):
        def __init__(self, location):
            pygame.sprite.Sprite.__init__(self)
            # 加载树的图片
            self.image = pygame.image.load('./ images/tree.png')
            # 初始化树的位置
            self.location = location
            # 获取图片大小
            self.rect = self.image.get_rect()
            # 指定图片中心位置
            self.rect.center = location
            self.type = 'tree'
        # 移动
        def update(self):
            global speedy
            self.rect.centery -=speedy
            # 判断树是否移除屏幕
            if self.rect.centery < -32:
                self.kill()
    
    # 旗子类
    class FlagClass(pygame.sprite.Sprite):
        def __init__(self, location):
            pygame.sprite.Sprite.__init__(self)
            # 加载旗子的图片
            self.image = pygame.image.load('./ images/flag.png')
            # 初始化位置
            self.location = location
            # 获取图片大小
            self.rect = self.image.get_rect()
            # 指定图片中心位置
            self.rect.center = location
            self.type = 'flag'
        # 移动
        def update(self):
            global speedy
            self.rect.centery -=speedy
            # 判断树是否移除屏幕
            if self.rect.centery < -32:
                self.kill()
    
    
    # 创建一个窗口,生成随机的树和小旗
    def create_map():
        global obstacles # 全局变量声明
        locations = []
        for i in range(30):  # 每屏30个障碍物
            row = random.randint(0, 9)  # 获得随机数在 start-end之间
            col = random.randint(0, 9)
            location = [row * 64 + 32, col * 64 + 32 + 640]  # 确定障碍物所在位置(x,y)
            if not (location in locations):  # 确保没有将两个障碍物放在同一个位置
                locations.append(location)
                # 将树添加到游戏
                obstacle_tree = TreeClass(location)
                # 将旗子添加到游戏
                obstacle_flag = FlagClass(location)
                # 将树或者旗子随机放入
                obstacles.add(random.choice([obstacle_tree,obstacle_flag]))
    
    # 更新游戏页面
    def updateGame():
        skier.move(speed)  # 滑雪者移动
        # 指定背景颜色为白色
        screen.fill([255, 255, 255])
        obstacles.draw(screen)  # 绘制障碍物在窗口中
        obstacles.update()  # 屏幕更新显示
        # 绘制图
        screen.blit(skier.image, skier.rect)
        # 屏幕更新显示
        pygame.display.update()
    
    
    # 初始化游戏
    pygame.init()
    
    # 初始化音频
    pygame.mixer.init()
    pygame.mixer.music.load("./music/bg_music.mp3")  # 加载音乐
    pygame.mixer.music.set_volume(0.4)  # 音量设置为0.4
    pygame.mixer.music.play(-1)  # 无线循环播放
    
    # 游戏窗口
    screen = pygame.display.set_mode((640, 640))  # 宽:640,高:640
    # 窗口标题
    pygame.display.set_caption('滑雪大冒险')
    # 创建滑雪者类的实例对象
    skier = SkierClass()
    # 设置移动的x轴距离
    speed = 0
    #设置时钟
    clock = pygame.time.Clock()
    # 创建独立运动的组织
    obstacles = pygame.sprite.Group()
    # 调用函数,生成树和旗子
    create_map()
    # 设置移动的x轴距离
    speedy = 6
    # 创建一个记录树和旗子移动到哪里的变量
    map_position = 0
    # 创建分数变量score
    score = 0
    # 创建一个font对象,控制字体大小
    font = pygame.font.Font(None, 50)
    
    
    #循环
    while True:
        # time.sleep(0.03)
        map_position += speedy
        if map_position >=640:
            create_map()
            map_position = 0
    
        clock.tick(30) #每秒钟执行30次
        # 监听所有事件
        for event in pygame.event.get():
            # 点击?号关闭,退出游戏
            if event.type == pygame.QUIT:
                #游戏退出
                pygame.quit()
            if event.type == pygame.KEYDOWN:
                # 如果点击左键则向左转
                if event.key == pygame.K_LEFT:
                    skier.turn(-1)
                    speed = -1
                # 如果点击右键则向右转
                elif event.key == pygame.K_RIGHT:
                    skier.turn(1)
                    speed = 1
    
        # 碰撞检测
        hit = pygame.sprite.spritecollide(skier, obstacles, False)
        if hit:
            # 如果碰到树
            if hit[0].type == 'tree':
                score -=50
                # 将树隐藏
                hit[0].kill()
                # 显示碰撞的图片
                skier.image = pygame.image.load("./ images/skier_fall.png")
                updateGame()
                # 摔倒后暂停一会重新再站起来
                time.sleep(1)
                skier.image = pygame.image.load('./ images/skier_forward.png')
                skier.angle = 0
                speed = 0
            elif hit[0].type == 'flag':
                score += 10
                hit[0].kill()
        updateGame()
    
    
        # 滑雪者移动
        skier.move(speed)
        # 白色背景
        screen.fill([255, 255, 255])
    
        # 把树和旗子绘制到窗口
        obstacles.draw(screen)
        # 屏幕更新显示
        obstacles.update()
    
        # 绘制滑雪者
        screen.blit(skier.image,skier.rect)
    
        # 显示得分
        score_text = font.render("Score: " + str(score), 1, (0, 0, 0))
        # 将分数绘制在指定位置
        screen.blit(score_text, [10, 10])
    
        # 刷新屏幕
        pygame.display.flip()
    
    

    五、玛丽冒险

    1.第一节课

    # 导入pygame
    import pygame
    
    SCREENWIDTH = 673  # 窗口宽度根据地图宽度定
    SCREENHEIGHT = 224  # 窗口高度根据地图高度定
    FPS = 30  # 4.更新画面时间
    
    # 定义一个移动地图类
    class MyMap():
        def __init__(self, x, y):
            # 加载背景图片
            self.bg = pygame.image.load("image/ditutu.png").convert_alpha()
            # 初始化x的坐标
            self.x = x
            # 初始化y的坐标
            self.y = y
    
        def map_rolling(self):
            if self.x < -673:  # 小于-673说明地图已经完全移动完毕
                self.x = 673  # 给地图一个新的坐标点
            else:
                self.x -= 5  # 向左移动5个像素
    
        # 更新地图
        def map_update(self):
            screen.blit(self.bg, (self.x, self.y))
    
    
    def mainGame():
        over = False  # 游戏结束标记
        global screen
    
        # 1.初始化游戏
        pygame.init()
        # 2.使用python时钟控制每个循环多长时间运行一次,在使用时钟前必须先创建clock对象的一个实例
        fpsclock = pygame.time.Clock()
        # 3.游戏窗口
        screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
        # 4.窗口标题
        pygame.display.set_caption('玛丽冒险')
    
    
        # 创建地图对象
        bg1 = MyMap(0, 0)
        bg2 = MyMap(673, 0)
    
        # 循环
        while True:
            # 监听所有事件
            for event in pygame.event.get():
                # 点击❌号关闭,退出游戏
                if event.type == pygame.QUIT:
                    # 游戏退出
                    pygame.quit()
                    
            if over == False:
                # 绘制地图,起到更新地图的作用
                bg1.map_update()
                # 地图移动
                bg1.map_rolling()
                bg2.map_update()
                bg2.map_rolling()
    
    
            # 5.更新整个窗体
            pygame.display.update()
            # 6.循环应该多长时间运行一次
            fpsclock.tick(FPS)
    
    if __name__ == '__main__':
        mainGame()
    

    思考:以上代码执行后,为何图片可以进行无缝衔接的滚动?

    回答:代码的逻辑实现了图片的无缝衔接滚动,主要是通过以下步骤和机制实现的:

  • 地图图片的加载: MyMap 类在初始化时加载了一个背景图片 ditutu.png,并设置了其 alpha通道(意味着该图片可能包含透明区域)。

  • 双地图机制: 创建了两个 MyMap 对象(bg1 和 bg2),它们分别表示屏幕上的两个相同的背景图。其中,bg1 初始位置在 (0,0),而 bg2 初始位置在 (673, 0)(与屏幕宽度相同,因此它在屏幕外开始)。

  • 地图的滚动: 在每个游戏循环中,map_rolling 方法会更新 bg1 和 bg2 的 x 坐标,使其向左移动 5 个像素。当 bg1的 x 坐标小于 -673(即完全移出屏幕)时,它会被重置到 673(即屏幕的右侧边界),这样它就可以再次从屏幕右侧开始滚动。由于 bg2始终与 bg1 保持相同的距离(673 像素),当 bg1 滚动并重新出现在屏幕右侧时,bg2 也会正好从屏幕左侧消失,从而实现无缝衔接。

  • 地图的绘制: 在每个游戏循环中,map_update 方法会在屏幕上绘制两个地图图片。由于 bg1 和 bg2 的初始位置以及它们的滚动方式,它们会在屏幕上形成一个连续的、无缝衔接的背景。

  • 屏幕更新: 在每个游戏循环的末尾,使用 pygame.display.update() 更新整个屏幕,显示最新的游戏状态。

  • 帧率控制: 通过 fpsclock.tick(FPS),游戏循环被限制为每秒运行 FPS(在这里是 30)次。这确保了游戏的流畅性和稳定性。

  • 通过上述机制,当 bg1 从屏幕右侧重新出现时,bg2 正好从左侧消失,玩家看到的是两个图片的无缝衔接滚动,从而实现了地图的循环滚动效果。

  • 2.第二节课

    # 导入pygame
    import pygame
    from itertools import cycle  # 导入迭代工具
    
    
    SCREENWIDTH = 673  # 窗口宽度根据地图宽度定
    SCREENHEIGHT = 224  # 窗口高度根据地图高度定
    FPS = 30  # 4.更新画面时间
    
    # 定义一个移动地图类
    class MyMap():
        def __init__(self, x, y):
            # 加载背景图片
            self.bg = pygame.image.load("image/ditutu.png").convert_alpha()
            # 初始化x的坐标
            self.x = x
            # 初始化y的坐标
            self.y = y
    
        def map_rolling(self):
            if self.x < -673:  # 小于-673说明地图已经完全移动完毕
                self.x = 673  # 给地图一个新的坐标点
            else:
                self.x -= 5  # 向左移动5个像素
    
        # 更新地图
        def map_update(self):
            screen.blit(self.bg, (self.x, self.y))
    
    # 玛丽类
    class Marie():
        def __init__(self):
            # 初始化玛丽矩形
            self.rect = pygame.Rect(0, 0, 0, 0)
            self.x = 50  # 绘制玛丽的x坐标
            self.lowest_y = 170  # 最低坐标
            self.y = self.lowest_y  # 绘制玛丽的y坐标
            self.rect.topleft = (self.x, self.y)
            # 加载玛丽图片
            self.adventure_img = (
                pygame.image.load("image/A.png").convert_alpha(),
                pygame.image.load("image/An.png").convert_alpha()
            )
            # 玛丽动图索引
            # self.marieIndex = 0
            self.marieIndexGen = cycle([0, 1])
    
            self.jumpState = False  # 跳跃的状态
            self.jumpHeight = 100  # 跳跃的高度
            self.jumpValue = 0  # 跳跃增变量
            self.jump_music = pygame.mixer.Sound("music/jump.wav")  # 跳音效
    
    
            # 绘制玛丽
        def draw_marie(self):
            # 匹配玛丽动图
            marieIndex = next(self.marieIndexGen)
            # 绘制玛丽
            screen.blit(self.adventure_img[marieIndex], (self.x, self.rect.y))
    
        # 跳状态
        def jump(self):
            self.jumpState = True
    
        # 玛丽移动
        def move(self):
            # 当起跳的时候
            if self.jumpState:
                # 如果站在地上
                if self.rect.y >= self.lowest_y:
                    # 以5个像素值向上移动
                    self.jumpValue = -5
                # 玛丽到达顶部回落
                if self.rect.y <= self.lowest_y - self.jumpHeight:
                    # 以5个像素值向下移动
                    self.jumpValue = 5
                # 通过循环改变玛丽的y坐标
                self.rect.y += self.jumpValue
                # 如果玛丽回到地面
                if self.rect.y >= self.lowest_y:
                    # 关闭跳跃状态
                    self.jumpState = False
    
    def mainGame():
        over = False  # 游戏结束标记
        global screen
    
        # 1.初始化游戏
        pygame.init()
        # 2.使用python时钟控制每个循环多长时间运行一次,在使用时钟前必须先创建clock对象的一个实例
        fpsclock = pygame.time.Clock()
        # 3.游戏窗口
        screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
        # 4.窗口标题
        pygame.display.set_caption('玛丽冒险')
    
    
        # 创建地图对象
        bg1 = MyMap(0, 0)
        bg2 = MyMap(673, 0)
    
        # 创建玛丽对象
        marie = Marie()
    
    
        # 循环
        while True:
            # 监听所有事件
            for event in pygame.event.get():
                # 点击❌号关闭,退出游戏
                if event.type == pygame.QUIT:
                    # 游戏退出
                    pygame.quit()
    
                # 按下键盘上的空格键,开启跳的状态
                if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                    # 1.如果玛丽在地面上
                    if marie.rect.y >= marie.lowest_y:
                        # 2.播放玛丽跳跃音效
                        marie.jump_music.play()
                        # 3.开启玛丽跳的状态
                        marie.jump()
    
    
            if over == False:
                # 绘制地图,起到更新地图的作用
                bg1.map_update()
                # 地图移动
                bg1.map_rolling()
                bg2.map_update()
                bg2.map_rolling()
                # 绘制玛丽
                marie.draw_marie()
                # 玛丽移动
                marie.move()
    
            # 5.更新整个窗体
            pygame.display.update()
            # 6.循环应该多长时间运行一次
            fpsclock.tick(FPS)
    
    if __name__ == '__main__':
        mainGame()
    

    3.第三节课

    # 导入pygame
    import pygame
    from itertools import cycle  # 导入迭代工具
    import random
    
    SCREENWIDTH = 673  # 窗口宽度根据地图宽度定
    SCREENHEIGHT = 224  # 窗口高度根据地图高度定
    FPS = 30  # 4.更新画面时间
    
    # 定义一个移动地图类
    class MyMap():
        def __init__(self, x, y):
            # 加载背景图片
            self.bg = pygame.image.load("image/ditutu.png").convert_alpha()
            # 初始化x的坐标
            self.x = x
            # 初始化y的坐标
            self.y = y
    
        def map_rolling(self):
            if self.x < -673:  # 小于-673说明地图已经完全移动完毕
                self.x = 673  # 给地图一个新的坐标点
            else:
                self.x -= 5  # 向左移动5个像素
    
        # 更新地图
        def map_update(self):
            screen.blit(self.bg, (self.x, self.y))
    
    # 玛丽类
    class Marie():
        def __init__(self):
            # 初始化玛丽矩形
            self.rect = pygame.Rect(0, 0, 0, 0)
            self.x = 50  # 绘制玛丽的x坐标
            self.lowest_y = 170  # 最低坐标
            self.y = self.lowest_y  # 绘制玛丽的y坐标
            self.rect.topleft = (self.x, self.y)
            # 加载玛丽图片
            self.adventure_img = (
                pygame.image.load("image/A.png").convert_alpha(),
                pygame.image.load("image/An.png").convert_alpha()
            )
            # 玛丽动图索引
            # self.marieIndex = 0
            self.marieIndexGen = cycle([0, 1])
    
            self.jumpState = False  # 跳跃的状态
            self.jumpHeight = 100  # 跳跃的高度
            self.jumpValue = 0  # 跳跃增变量
            self.jump_music = pygame.mixer.Sound("music/jump.wav")  # 跳音效
    
    
            # 绘制玛丽
        def draw_marie(self):
            # 匹配玛丽动图
            marieIndex = next(self.marieIndexGen)
            # 绘制玛丽
            screen.blit(self.adventure_img[marieIndex], (self.x, self.rect.y))
    
        # 跳状态
        def jump(self):
            self.jumpState = True
    
        # 玛丽移动
        def move(self):
            # 当起跳的时候
            if self.jumpState:
                # 如果站在地上
                if self.rect.y >= self.lowest_y:
                    # 以5个像素值向上移动
                    self.jumpValue = -5
                # 玛丽到达顶部回落
                if self.rect.y <= self.lowest_y - self.jumpHeight:
                    # 以5个像素值向下移动
                    self.jumpValue = 5
                # 通过循环改变玛丽的y坐标
                self.rect.y += self.jumpValue
                # 如果玛丽回到地面
                if self.rect.y >= self.lowest_y:
                    # 关闭跳跃状态
                    self.jumpState = False
    
    # 障碍物类
    class obstacle():
        def __init__(self):
            # 初始化障碍物矩形
            self.rect = pygame.Rect(0, 0, 0, 0)
            # 加载障碍物图片
            self.missile = pygame.image.load("image/missile.png")
            self.pipe = pygame.image.load("image/pipe.png")
            # 0和1随机数判断是管道还是导弹
            number = random.randint(0, 1)
            if number == 0:  # 如果随机数为0显示导弹障碍物相反显示管道
                self.image = self.missile  # 显示导弹障碍
                self.move = 15  # 导弹移动速度加快
                self.obstacle_y = 150  # 导弹坐标在天上
            else:
                self.image = self.pipe  # 显示管道障碍
                self.move = 5  # 管道移动速度慢
                self.obstacle_y = 160  # 管道在地面上
            # 障碍物绘制坐标
            self.rect.x = 673
            self.rect.y = self.obstacle_y
    
        # 障碍物移动
        def obstacle_move(self):
            self.rect.x -= self.move
    
        # 绘制障碍物
        def draw_obstacle(self):
            screen.blit(self.image, (self.rect.x, self.rect.y))
    
    
    def mainGame():
        over = False  # 游戏结束标记
        global screen
    
        # 1.初始化游戏
        pygame.init()
        # 2.使用python时钟控制每个循环多长时间运行一次,在使用时钟前必须先创建clock对象的一个实例
        fpsclock = pygame.time.Clock()
        # 3.游戏窗口
        screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
        # 4.窗口标题
        pygame.display.set_caption('玛丽冒险')
    
    
        # 创建地图对象
        bg1 = MyMap(0, 0)
        bg2 = MyMap(673, 0)
    
        # 创建玛丽对象
        marie = Marie()
    
        # 添加障碍物的时间
        addobstacleTimer = 0
        # 障碍物对象列表
        list = []
    
    
        # 循环
        while True:
            # 监听所有事件
            for event in pygame.event.get():
                # 点击❌号关闭,退出游戏
                if event.type == pygame.QUIT:
                    # 游戏退出
                    pygame.quit()
    
                # 按下键盘上的空格键,开启跳的状态
                if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                    # 1.如果玛丽在地面上
                    if marie.rect.y >= marie.lowest_y:
                        # 2.播放玛丽跳跃音效
                        marie.jump_music.play()
                        # 3.开启玛丽跳的状态
                        marie.jump()
    
    
            if over == False:
                # 绘制地图,起到更新地图的作用
                bg1.map_update()
                # 地图移动
                bg1.map_rolling()
                bg2.map_update()
                bg2.map_rolling()
                # 绘制玛丽
                marie.draw_marie()
                # 玛丽移动
                marie.move()
    
                # 计算障碍物间隔时间
                if addobstacleTimer >= 1200:
                    # 创建障碍物对象
                    obs = obstacle()
                    # 将障碍物对象添加到列表中
                    list.append(obs)
                    # 重置添加障碍物时间
                    addobstacleTimer = 0
    
                # 循环遍历障碍物
                for i in range(len(list)):
                    # 障碍物移动
                    list[i].obstacle_move()
                    # 绘制障碍物
                    list[i].draw_obstacle()
    
            # 增加障碍物时间
            addobstacleTimer += 20
            # 5.更新整个窗体
            pygame.display.update()
            # 6.循环应该多长时间运行一次
            fpsclock.tick(FPS)
    
    if __name__ == '__main__':
        mainGame()
    

    4.第四节课

    # 导入pygame
    import pygame
    from itertools import cycle  # 导入迭代工具
    import random
    
    SCREENWIDTH = 673  # 窗口宽度根据地图宽度定
    SCREENHEIGHT = 224  # 窗口高度根据地图高度定
    FPS = 40  # 4.更新画面时间
    
    # 游戏结束
    def game_over():
        bump_music = pygame.mixer.Sound("music/bump.wav")  # 撞击
        bump_music.play()  # 播放撞击音效
        # 加载游戏结束的图片
        over_img = pygame.image.load("image/gameover.png")
        # 将游戏结束的图片绘制在窗体的中间位置
        screen.blit(over_img, (230, 90))
    
    
    def mainGame():
        score = 0  # 得分
        over = False  # 游戏结束标记
        global screen
    
        # 1.初始化游戏
        pygame.init()
        # 2.使用python时钟控制每个循环多长时间运行一次,在使用时钟前必须先创建clock对象的一个实例
        fpsclock = pygame.time.Clock()
        # 3.游戏窗口
        screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
        # 4.窗口标题
        pygame.display.set_caption('玛丽冒险')
    
        # 创建地图对象
        bg1 = MyMap(0, 0)
        bg2 = MyMap(673, 0)
        # 创建玛丽对象
        marie = Marie()
    
        # 添加障碍物的时间
        addobstacleTimer = 0
        # 障碍物对象列表
        list = []
    
        # 循环
        while True:
            # 监听所有事件
            for event in pygame.event.get():
                # 点击❌号关闭,退出游戏
                if event.type == pygame.QUIT:
                    # 游戏退出
                    pygame.quit()
    
                # 按下键盘上的空格键,开启跳的状态
                if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                    # 1.如果玛丽在地面上
                    if marie.rect.y >= marie.lowest_y:
                        # 2.播放玛丽跳跃音效
                        marie.jump_music.play()
                        # 3.开启玛丽跳的状态
                        marie.jump()
    
            if over == False:
            # 绘制地图,起到更新地图的作用
                bg1.map_update()
                # 地图移动
                bg1.map_rolling()
                bg2.map_update()
                bg2.map_rolling()
                # 绘制玛丽
                marie.draw_marie()
                # 玛丽移动
                marie.move()
    
                # 计算障碍物间隔时间
                if addobstacleTimer >= 1200:
                    # 创建障碍物对象
                    obs = obstacle()
                    # 将障碍物对象添加到列表中
                    list.append(obs)
                    # 重置添加障碍物时间
                    addobstacleTimer = 0
    
                list1 = []
    
                # 循环遍历障碍物
                for i in range(len(list)):
                    # 障碍物移动
                    list[i].obstacle_move()
                    # 绘制障碍物
                    list[i].draw_obstacle()
    
                    if list[i].rect.x < -50:
                        # 加分
                        score += 1
                        list1.append(list[i])
    
                    # 判断玛丽与障碍物是否碰撞
                    if pygame.sprite.collide_rect(marie, list[i]):
                        # 碰撞后开启结束开关
                        over = True
                        # 调用游戏结束的方法
                        game_over()
    
                     # 显示分数
                    list[i].showScore(score)
    
                for i in list1:
                    list.remove(i)
    
            # 增加障碍物时间
            addobstacleTimer += 20
    
    
            # 5.更新整个窗体
            pygame.display.update()
            # 6.循环应该多长时间运行一次
            fpsclock.tick(FPS)
    
    # 地图类
    class MyMap():
        def __init__(self, x, y):
            # 加载背景图片
            self.bg = pygame.image.load("image/ditutu.png").convert_alpha()
            # 初始化x的坐标
            self.x = x
            # 初始化y的坐标
            self.y = y
        
        # 地图滚动
        def map_rolling(self):
            if self.x < -673:  # 小于-673说明地图已经完全移动完毕
                self.x = 673  # 给地图一个新的坐标点
            else:
                self.x -= 5  # 向左移动5个像素
    
        # 更新地图
        def map_update(self):
            screen.blit(self.bg, (self.x, self.y))
    
    
    # 玛丽类
    class Marie():
        def __init__(self):
            # 初始化玛丽矩形
            self.rect = pygame.Rect(0, 0, 0, 0)
            self.x = 50  # 绘制玛丽的x坐标
            self.lowest_y = 170  # 最低坐标
            self.y = self.lowest_y  # 绘制玛丽的y坐标
            self.rect.topleft = (self.x, self.y)
            # 加载玛丽图片
            self.adventure_img = (
                pygame.image.load("image/A.png").convert_alpha(),
                pygame.image.load("image/An.png").convert_alpha()
            )
            self.marieIndexGen = cycle([0, 1])
    
            self.jumpState = False  # 跳跃的状态
            self.jumpHeight = 100  # 跳跃的高度
            self.jumpValue = 0  # 跳跃增变量
            self.jump_music = pygame.mixer.Sound("music/jump.wav")  # 跳音效
    
            self.rect.size = self.adventure_img[0].get_size()
    
        # 绘制玛丽
        def draw_marie(self):
            # 匹配玛丽动图
            marieIndex = next(self.marieIndexGen)
            # 绘制玛丽
            screen.blit(self.adventure_img[marieIndex], (self.x, self.rect.y))
    
        # 跳状态
        def jump(self):
            self.jumpState = True
    
    
        # 玛丽移动
        def move(self):
            # 当起跳的时候
            if self.jumpState:
                # 如果站在地上
                if self.rect.y >= self.lowest_y:
                    # 以5个像素值向上移动
                    self.jumpValue = -5
                # 玛丽到达顶部回落
                if self.rect.y <= self.lowest_y - self.jumpHeight:
                    # 以5个像素值向下移动
                    self.jumpValue = 5
                # 通过循环改变玛丽的y坐标
                self.rect.y += self.jumpValue
                # 如果玛丽回到地面
                if self.rect.y >= self.lowest_y:
                    # 关闭跳跃状态
                    self.jumpState = False
    
    # 障碍物类
    class obstacle():
        def __init__(self):
            # 初始化障碍物矩形
            self.rect = pygame.Rect(0, 0, 0, 0)
            # 加载障碍物图片
            self.missile = pygame.image.load("image/missile.png")
            self.pipe = pygame.image.load("image/pipe.png")
            # 加载分数图片
            self.numbers = (pygame.image.load("image/0.png"),
                            pygame.image.load("image/1.png"),
                            pygame.image.load("image/2.png"),
                            pygame.image.load("image/3.png"),
                            pygame.image.load("image/4.png"),
                            pygame.image.load("image/5.png"),
                            pygame.image.load("image/6.png"),
                            pygame.image.load("image/7.png"),
                            pygame.image.load("image/8.png"),
                            pygame.image.load("image/9.png"))
            # 0和1随机数判断是管道还是导弹
            number = random.randint(0, 1)
            if number == 0:  # 如果随机数为0显示导弹障碍物相反显示管道
                self.image = self.missile  # 显示导弹障碍
                self.move = 15  # 导弹移动速度加快
                self.obstacle_y = 150  # 导弹坐标在天上
                self.rect.size = self.image.get_size()
            else:
                self.image = self.pipe  # 显示管道障碍
                self.move = 5  # 管道移动速度慢
                self.obstacle_y = 160  # 管道在地面上
                self.rect.size = self.image.get_size()
            # 障碍物绘制坐标
            self.rect.x = 673
            self.rect.y = self.obstacle_y
    
        # 障碍物移动
        def obstacle_move(self):
            self.rect.x -= self.move
    
        # 绘制障碍物
        def draw_obstacle(self):
            screen.blit(self.image, (self.rect.x, self.rect.y))
    
        # 显示分数
        def showScore(self, score):
            # 分数横向位置
            X = 546
            a = list(str(score))
            for i in a:
                # 绘制分数
                screen.blit(self.numbers[int(i)], (X, 22.4))
                # 随着数字增加改变位置
                X += 24
    
    
    if __name__ == '__main__':
        mainGame()
    

    六、创意课-flappy bird

    1.地图

    import pygame
    import random
    
    # 游戏窗口
    SCREENWIDTH = 500  # 窗口宽度根据地图宽度定
    SCREENHEIGHT = 375  # 窗口高度根据地图高度定
    FPS = 30  # 更新画面时间
    
    
    # 地图类
    class MyMap():
        def __init__(self, x, y):
            # 加载背景图片
            self.bg = pygame.image.load("image/地图.jpg").convert_alpha()
            # 初始化x的坐标
            self.x = x
            # 初始化y的坐标
            self.y = y
    
    
        # 地图滚动
        def map_rolling(self):
            if self.x < -490:  # 地图已经完全移动完毕
                self.x = 500  # 给地图一个新的坐标点
            else:
                self.x -= 5  # 向左移动5个像素
    
        # 更新地图
        def map_update(self):
            screen.blit(self.bg, (self.x, self.y))
    
    
    # 游戏主入口
    def mainGame():
        over = False  # 游戏结束标记
        global screen
        # 1.初始化窗口
        pygame.init()
        # 2.使用python时钟控制每个循环多长时间运行一次,在使用时钟前必须先创建clock对象的一个实例
        fpsclock = pygame.time.Clock()
        # 3.设置窗口大小
        screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
        # 4.设置窗口标题
        pygame.display.set_caption("钢管鸟")
    
        # 创建地图对象
        bg1 = MyMap(0, 0)
        bg2 = MyMap(500, 0)
    
    
        while True:
            # 获取单击事件
            for event in pygame.event.get():
                # 如果单击了关闭窗体就将窗体关闭
                if event.type == pygame.QUIT:
                    pygame.quit()  # 退出窗口
    
            if over == False:
                # 绘制地图,起到更新地图的作用
                bg1.map_update()
                bg2.map_update()
                # 地图移动
                bg1.map_rolling()
                bg2.map_rolling()
    
            # 更新整个窗体
            pygame.display.update()
            # 循环应该多长时间运行一次
            fpsclock.tick(FPS)
    
    
    
    if __name__ == '__main__':
        mainGame()
    

    2.鸟类

    import pygame
    import random
    
    # 游戏窗口
    SCREENWIDTH = 500  # 窗口宽度根据地图宽度定
    SCREENHEIGHT = 375  # 窗口高度根据地图高度定
    FPS = 30  # 更新画面时间
    
    
    # 地图类
    class MyMap():
        def __init__(self, x, y):
            # 加载背景图片
            self.bg = pygame.image.load("image/地图.jpg").convert_alpha()
            # 初始化x的坐标
            self.x = x
            # 初始化y的坐标
            self.y = y
    
    
        # 地图滚动
        def map_rolling(self):
            if self.x < -490:  # 地图已经完全移动完毕
                self.x = 500  # 给地图一个新的坐标点
            else:
                self.x -= 5  # 向左移动5个像素
    
        # 更新地图
        def map_update(self):
            screen.blit(self.bg, (self.x, self.y))
    
    
    # 鸟类
    class Bird():
        def __init__(self):
            # 初始化矩形
            self.rect = pygame.Rect(0, 0, 0, 0)
            # 加载图片
            self.adventure_img = pygame.image.load("image/鸟.png")
            self.rect.size = self.adventure_img.get_size()
            self.x = 150  # 绘制x坐标
            self.y = 150
            self.rect.topleft = (self.x, self.y)
    
        # 绘制
        def draw_marie(self):
            screen.blit(self.adventure_img, (self.x, self.rect.y))
    
            #鸟上升20
        def jump(self):
            self.rect.y -= 20
    
        #鸟下降2 
        def move(self):
            print(666)
            self.rect.y += 2
    
    
    
    
    # 游戏主入口
    def mainGame():
        over = False  # 游戏结束标记
        global screen
        # 1.初始化窗口
        pygame.init()
        # 2.使用python时钟控制每个循环多长时间运行一次,在使用时钟前必须先创建clock对象的一个实例
        fpsclock = pygame.time.Clock()
        # 3.设置窗口大小
        screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
        # 4.设置窗口标题
        pygame.display.set_caption("钢管鸟")
    
        # 创建地图对象
        bg1 = MyMap(0, 0)
        bg2 = MyMap(500, 0)
        bird = Bird()
    
    
        while True:
            # 获取单击事件
            for event in pygame.event.get():
                # 如果单击了关闭窗体就将窗体关闭
                if event.type == pygame.QUIT:
                    pygame.quit()  # 退出窗口
    
                # 按下键盘上的空格键,开启跳的状态
                if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                    # 跳
                    bird.jump()
                    if over == True:
                        mainGame()
    
            if over == False:
                # 绘制地图,起到更新地图的作用
                bg1.map_update()
                bg2.map_update()
                # 地图移动
                bg1.map_rolling()
                bg2.map_rolling()
                # 绘制小鸟
                bird.draw_marie()
                # 小鸟移动
                bird.move()
    
            # 更新整个窗体
            pygame.display.update()
            # 循环应该多长时间运行一次
            fpsclock.tick(FPS)
    
    
    
    if __name__ == '__main__':
        mainGame()
    

    3.管道

    在这里插入代码片
    

    4.最终代码

    import pygame
    import random
    
    SCREENWIDTH = 500  # 窗口宽度根据地图宽度定
    SCREENHEIGHT = 375  # 窗口高度根据地图高度定
    FPS = 30  # 更新画面时间
    
    # 定义一个移动地图类
    class MyMap():
        def __init__(self, x, y):
            # 加载背景图片
            self.bg = pygame.image.load("image/地图.jpg").convert_alpha()
            # 初始化x的坐标
            self.x = x
            # 初始化y的坐标
            self.y = y
    
        # 地图滚动
        def map_rolling(self):
            if self.x < -490:  # 地图已经完全移动完毕
                self.x = 500  # 给地图一个新的坐标点
            else:
                self.x -= 5  # 向左移动5个像素
                
        # 更新地图
        def map_update(self):
            screen.blit(self.bg, (self.x, self.y))
    
    # 鸟类
    class Bird():
        def __init__(self):
            # 初始化矩形
            self.rect = pygame.Rect(0, 0, 0, 0)
            # 加载图片
            self.adventure_img = pygame.image.load("image/鸟.png")
            self.rect.size = self.adventure_img.get_size()
            self.x = 150  # 绘制x坐标
            self.y = 150
            self.rect.topleft = (self.x, self.y)
            
        # 绘制
        def draw_marie(self):
            screen.blit(self.adventure_img, (self.x, self.rect.y))
    
        #鸟上升20
        def jump(self):
            self.rect.y -= 20
    
    
        #鸟下降2 
        def move(self):
            self.rect.y += 2
    
    
    # 下管道类
    class Wall():
        def __init__(self):
            # 初始化障碍物矩形
            self.rect = pygame.Rect(0, 0, 0, 0)
            # 加载障碍物图片
            self.image = pygame.image.load("image/上管道.png")
            # 纵坐标随机生成
            number = random.randint(190, 300)
            self.rect.size = self.image.get_size()
            self.move = 10  # 移动速度
            # 障碍物绘制坐标
            self.rect.x = 520
            self.rect.y = number
    
        # 障碍物移动
        def obstacle_move(self):
            self.rect.x -= self.move
            if self.rect.x < -100:
                self.rect.x = 520
                self.rect.y = random.randint(190, 300)
    
        # 绘制障碍物
        def draw_obstacle(self):
            screen.blit(self.image, (self.rect.x, self.rect.y))
    
    
    # 上管道类
    class Wall2():
        def __init__(self):
            # 初始化障碍物矩形
            self.rect = pygame.Rect(0, 0, 0, 0)
            # 加载障碍物图片
            self.image = pygame.image.load("image/下管道.png")
            # 纵坐标随机生成
            number = random.randint(-150, -30)
            self.rect.size = self.image.get_size()
            self.move = 10  # 墙移动速度
            # 障碍物绘制坐标
            self.rect.x = 520
            self.rect.y = number
    
        # 障碍物移动
        def obstacle_move(self):
            self.rect.x -= self.move
            if self.rect.x < -100:
                self.rect.x = 520
                self.rect.y = random.randint(-150, -30)
    
    
        # 绘制障碍物
        def draw_obstacle(self):
            screen.blit(self.image, (self.rect.x, self.rect.y))
    
    # 游戏主函数入口
    def mainGame():
        over = False  # 游戏结束标记
        global screen
        # 1.初始化窗口
        pygame.init()
        # 2.使用python时钟控制每个循环多长时间运行一次,在使用时钟前必须先创建clock对象的一个实例
        fpsclock = pygame.time.Clock()
        # 3.设置窗口大小
        screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
        # 4.设置窗口标题
        pygame.display.set_caption("钢管鸟")
        # 创建地图对象
        bg1 = MyMap(0, 0)
        bg2 = MyMap(500, 0)
        # 创建鸟对象
        bird = Bird()
        # 创建下管道对象
        wall = Wall()
        # 创建上管道对象
        wall2 = Wall2()
    
    
        while True:
            # 获取单击事件
            for event in pygame.event.get():
                # 如果单击了关闭窗体就将窗体关闭
                if event.type == pygame.QUIT:
                    pygame.quit()  # 退出窗口
                # 按下键盘上的空格键,开启跳的状态
                if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                    # 跳
                    bird.jump()
                    if over == True:
                        mainGame()
    
            if over == False:
                # 绘制地图,起到更新地图的作用
                bg1.map_update()
                bg2.map_update()
                # 地图移动
                bg1.map_rolling()
                bg2.map_rolling()
                # 绘制小鸟
                bird.draw_marie()
                # 小鸟移动
                bird.move()
                # 绘制管道
                wall.draw_obstacle()
                wall2.draw_obstacle()
                # 管道移动
                wall.obstacle_move()
                wall2.obstacle_move()
    
                # 判断碰撞
                if pygame.sprite.collide_rect(bird, wall) or pygame.sprite.collide_rect(bird, wall2):
                    # 碰撞后开启结束开关
                    over = True
                
                
            # 更新整个窗体
            pygame.display.update()
            # 循环应该多长时间运行一次
            fpsclock.tick(FPS)
    
    
    if __name__ == '__main__':
        mainGame()
    

    作者:巨人张

    物联沃分享整理
    物联沃-IOTWORD物联网 » Pygame零基础入门教程

    发表回复