Bootstrap

pygame零基础入门

一、初始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()
;