20231326 王荣盛 2023-2024-2《Python程序设计》实验四报告

20231326 王荣盛 2023-2024-2《Python程序设计》实验四报告


课程:《Python程序设计》
班级:2313班
姓名: 王荣盛
学号: 20231326
实验教师:王志强
实验日期:2024年5月15日
必修/选修: 公选课

1. 实验内容

使用pygame库设计一款小游戏——打砖块小游戏

  • 有必要的用户交互
  • 有随机性
  • 可重复进行游戏

2. 实验设计

初始化与基础设置

初始化

import pygame
import random

pygame.init()

需要在对应环境目录下安装pygame库:pip install pygame

设置窗体
建立一个游戏窗口,大小为800*600,标题为“打砖块”

screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("打砖块")

颜色
定义要使用的颜色:

# name = rgb value
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
green = (0, 255, 0)
yellow = (255, 255, 0)

设置游戏元素

玩家控制的板子

paddle_width = 100
paddle_height = 10
paddle_pos = [screen_width // 2 - paddle_width // 2, screen_height - paddle_height - 10]
paddle_speed = 10

其中,变量paddle_pos是一个列表,其两个元素分别表示板子在屏幕上的初始横坐标(x坐标)和纵坐标(y坐标)。

  • screen_width // 2 - paddle_width // 2:将屏幕的中点减去板子的半宽度,可以使板子水平居中。
  • screen_height - paddle_height - 10:将屏幕高度减去板子的高度,再减去10,保证板子与屏幕底部保持10的距离。

ball_size = 10
ball_pos = [screen_width // 2, screen_height // 2]
ball_speed = [5, -5]

砖块

brick_rows = 5		# 砖块的行数
brick_cols = 10		# 砖块的列数
brick_width = (screen_width - 20) // brick_cols
brick_height = 20
brick_padding = 5	#砖块的间距
num_bricks = brick_rows * brick_cols	# 砖块的数目

其中,砖块的宽度视屏幕宽度动态调整。假设屏幕宽度为800像素,那么每个砖块的宽度为 (800 - 20) // 10 = 78 像素。

游戏机制

随机生成砖块

def create_bricks():
    bricks = []
    positions = [(x, y) for x in range(0, screen_width - brick_width, brick_width + brick_padding)
                 for y in range(0, screen_height // 2, brick_height + brick_padding)]
    random.shuffle(positions)
    for i in range(num_bricks):
        brick_x, brick_y = positions[i]
        bricks.append(pygame.Rect(brick_x, brick_y, brick_width, brick_height))
    return bricks


bricks = create_bricks()
  • 使创建bricks空列表存储砖块,使用positions存储砖块的左上角的位置。

    • x 坐标在 0screen_width - brick_width 之间,步长为 brick_width + brick_padding
    • y 坐标在 0screen_height // 2 之间,步长为brick_heigh + brick_padding
  • 使用random.shuffle()对列表positions随机化,从而使砖块的位置随机。

  • positions中不断取出位置x y,使用pygame.Rect(x, y, width, height)创建矩形对象代表砖块,并加入bricks列表之中。

游戏循环

  • 在游戏未结束的情况下,持续执行:
    • 处理事件:通过遍历事件队列,检查是否有退出事件。

    • 检测玩家的键盘输入,根据按键控制玩家板子的移动。

    • 移动球的位置,根据球的速度更新球的坐标。

    • [球的反弹机制与得分机制]

      • 如果球碰到了屏幕的左右边界,球的水平速度反向。
      • 如果球碰到了屏幕的上边界,球的竖直速度反向。
      • 如果球碰到了玩家板子,球的竖直速度反向。
      • 如果球碰到了砖块,球的速度会反弹,并移除被碰撞的砖块,增加得分。
    • [结束游戏条件] 如果球触底(超出屏幕底部)或者得分达到 50 分,则游戏结束.

绘制

在游戏进行的循环之中:

# 填充屏幕背景
screen.fill(black)

# 绘制玩家板子
pygame.draw.rect(screen, blue, (paddle_pos[0], paddle_pos[1], paddle_width, paddle_height))

# 绘制球
pygame.draw.circle(screen, red, ball_pos, ball_size)

# 绘制砖块
for brick in bricks:
	pygame.draw.rect(screen, green, brick)

# 显示得分
font = pygame.font.SysFont("monospace", 35)
score_text = font.render("Score: " + str(score), 1, white)
score_pos = score_text.get_rect(bottomright=(screen_width - 10, screen_height - 10))
screen.blit(score_text, score_pos)

pygame.display.update()

clock.tick(30)	# 游戏帧率

开始游戏界面:

def start_screen():
    selected_speed = 0
    while True:
        screen.fill(black)
        font = pygame.font.SysFont("monospace", 25)
        title_text = font.render("Welcome to Brick Breaker!", 1, white)
        screen.blit(title_text, (screen_width // 2 - title_text.get_width() // 2, 100))

        speed_text = font.render("Select Speed:", 1, white)
        screen.blit(speed_text, (screen_width // 2 - speed_text.get_width() // 2, 200))

        easy_text = font.render("1 - Easy", 1, white)
        screen.blit(easy_text, (screen_width // 2 - easy_text.get_width() // 2, 250))

        medium_text = font.render("2 - Hard", 1, white)
        screen.blit(medium_text, (screen_width // 2 - medium_text.get_width() // 2, 280))

        hard_text = font.render("3 - Very Hard", 1, white)
        screen.blit(hard_text, (screen_width // 2 - hard_text.get_width() // 2, 310))

        pygame.display.update()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                return
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_1:
                    selected_speed = 1
                elif event.key == pygame.K_2:
                    selected_speed = 2
                elif event.key == pygame.K_3:
                    selected_speed = 2.5

                if selected_speed in [1, 2, 2.5]:
                    return selected_speed

结束游戏界面:

def end_screen(score):
    while True:
        screen.fill(black)
        font = pygame.font.SysFont("monospace", 25)  # 调整字体大小
        if score == 50:
            score_text = font.render("You win! You got " + str(score) + " score!!!", 1, white)
        else:
            score_text = font.render("Game over! Final Score: " + str(score), 1, white)
        screen.blit(score_text, (screen_width // 2 - score_text.get_width() // 2, screen_height // 2 - 30))
        end_text = font.render("Press R to Restart or Q to Quit", 1, yellow)
        screen.blit(end_text, (screen_width // 2 - end_text.get_width() // 2, screen_height // 2 + 10))

        pygame.display.update()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r:
                    return True
                if event.key == pygame.K_q:
                    return False

3. 实验代码

'''

    srar.py
    简介: 一个简单的具有随机性的打砖块小游戏
    作者: 20231326 wrs
    最终审查时间: 2024/05/29

'''

import pygame
import random

# 初始化Pygame
pygame.init()


# 设置窗体
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("打砖块")

# 调色板,定义颜色
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
green = (0, 255, 0)
yellow = (255, 255, 0)

# 游戏元素
# 玩家板子
paddle_width = 100
paddle_height = 10
paddle_pos = [screen_width // 2 - paddle_width // 2, screen_height - paddle_height - 10]
paddle_speed = 10

# 球
ball_size = 10
ball_pos = [screen_width // 2, screen_height // 2]
ball_speed = [5, -5]

# 砖块
brick_rows = 5
brick_cols = 10
brick_width = (screen_width - 20) // brick_cols
brick_height = 20
brick_padding = 5
num_bricks = brick_rows * brick_cols


# 创建砖块
def create_bricks():
    bricks = []
    positions = [(x, y) for x in range(0, screen_width - brick_width, brick_width + brick_padding)
                 for y in range(0, screen_height // 2, brick_height + brick_padding)]
    random.shuffle(positions)
    for i in range(num_bricks):
        brick_x, brick_y = positions[i]
        bricks.append(pygame.Rect(brick_x, brick_y, brick_width, brick_height))
    return bricks


bricks = create_bricks()

# 设置游戏时钟
clock = pygame.time.Clock()


# 游戏循环
# 游戏循环
def game_loop(speed):
    global bricks
    global paddle_speed
    global ball_speed

    paddle_pos = [screen_width // 2 - paddle_width // 2, screen_height - paddle_height - 10]
    ball_pos = [screen_width // 2, screen_height // 2]
    paddle_speed = 8 * speed
    ball_speed = [3 * speed, -3 * speed]
    bricks = create_bricks()
    score = 0
    game_over = False

    # 输入检测
    while not game_over:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return False

        keys = pygame.key.get_pressed()

        if keys[pygame.K_LEFT] and paddle_pos[0] > 0:
            paddle_pos[0] -= paddle_speed
        if keys[pygame.K_RIGHT] and paddle_pos[0] < screen_width - paddle_width:
            paddle_pos[0] += paddle_speed

        # 球的运动
        # 移动球
        ball_pos[0] += ball_speed[0]
        ball_pos[1] += ball_speed[1]

        # 球碰到左右边界
        if ball_pos[0] <= 0 or ball_pos[0] >= screen_width - ball_size:
            ball_speed[0] = -ball_speed[0]

        # 球碰到上边界
        if ball_pos[1] <= 0:
            ball_speed[1] = -ball_speed[1]

        # 球碰到玩家板子
        if (paddle_pos[0] < ball_pos[0] < paddle_pos[0] + paddle_width and
                paddle_pos[1] < ball_pos[1] + ball_size < paddle_pos[1] + paddle_height):
            ball_speed[1] = -ball_speed[1]

        # 球碰到砖块
        for brick in bricks[:]:
            if brick.colliderect(pygame.Rect(ball_pos[0], ball_pos[1], ball_size, ball_size)):
                ball_speed[1] = -ball_speed[1]
                bricks.remove(brick)
                score += 1
                break

        # 检查游戏是否结束
        if ball_pos[1] >= screen_height or score == 50:
            game_over = True

        # 元素绘制
        # 填充屏幕背景
        screen.fill(black)

        # 绘制玩家板子
        pygame.draw.rect(screen, blue, (paddle_pos[0], paddle_pos[1], paddle_width, paddle_height))

        # 绘制球
        pygame.draw.circle(screen, red, ball_pos, ball_size)

        # 绘制砖块
        for brick in bricks:
            pygame.draw.rect(screen, green, brick)

        # 显示得分
        font = pygame.font.SysFont("monospace", 35)
        score_text = font.render("Score: " + str(score), 1, white)
        score_pos = score_text.get_rect(bottomright=(screen_width - 10, screen_height - 10))
        screen.blit(score_text, score_pos)

        pygame.display.update()
        clock.tick(60)

    return end_screen(score)


def start_screen():
    selected_speed = 0
    while True:
        screen.fill(black)
        font = pygame.font.SysFont("monospace", 25)
        title_text = font.render("Welcome to Brick Breaker!", 1, white)
        screen.blit(title_text, (screen_width // 2 - title_text.get_width() // 2, 100))

        speed_text = font.render("Select Speed:", 1, white)
        screen.blit(speed_text, (screen_width // 2 - speed_text.get_width() // 2, 200))

        easy_text = font.render("1 - Easy", 1, white)
        screen.blit(easy_text, (screen_width // 2 - easy_text.get_width() // 2, 250))

        medium_text = font.render("2 - Hard", 1, white)
        screen.blit(medium_text, (screen_width // 2 - medium_text.get_width() // 2, 280))

        hard_text = font.render("3 - Very Hard", 1, white)
        screen.blit(hard_text, (screen_width // 2 - hard_text.get_width() // 2, 310))

        pygame.display.update()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                return
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_1:
                    selected_speed = 1
                elif event.key == pygame.K_2:
                    selected_speed = 2
                elif event.key == pygame.K_3:
                    selected_speed = 2.5

                if selected_speed in [1, 2, 2.5]:
                    return selected_speed


# 结束屏幕
def end_screen(score):
    while True:
        screen.fill(black)
        font = pygame.font.SysFont("monospace", 25)  # 调整字体大小
        if score == 50:
            score_text = font.render("You win! You got " + str(score) + " score!!!", 1, white)
        else:
            score_text = font.render("Game over! Final Score: " + str(score), 1, white)
        screen.blit(score_text, (screen_width // 2 - score_text.get_width() // 2, screen_height // 2 - 30))
        end_text = font.render("Press R to Restart or Q to Quit", 1, yellow)
        screen.blit(end_text, (screen_width // 2 - end_text.get_width() // 2, screen_height // 2 + 10))

        pygame.display.update()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r:
                    return True
                if event.key == pygame.K_q:
                    return False


# 主程序
running = True
while running:
    selected_speed = start_screen()
    if selected_speed:
        running = game_loop(selected_speed)

pygame.quit()

4. 代码打包

使用pyinstaller打包成可运行程序:

pip install pyinstaller
pyinstaller --onefile --windowed srar.py

5. 实验结果

游戏视频:

打砖块

开始界面:
begin
游戏界面:
gaming
结束界面:
end

6. 实验遇到的问题与实验感想

问题

  • 在创建碰撞机制时,没有认识到反弹机制的原理,错误地将求的速度的两个维度均取反,以至于无论如何碰撞,小球将原路返回,这不符合碰撞原理。
  • 在游戏进行的循环中,游戏画面静止但游戏仍在继续,经检查发现没有使用pygame.display.update()刷新。

感想

在这次实验中,我综合运用了Pygame、列表操作和随机数生成,成功地实现了一个简单但有趣的小游戏。通过这个游戏,我展示了我在这学期以来的学习成果,特别是在Python编程方面的进步。这次实验不仅仅是对知识的应用,更是对我编程能力的一次考验和展示。
通过这个小游戏项目,我学会了如何使用Pygame库来创建游戏窗口、绘制图形和处理用户输入。同时,我还学会了如何利用列表操作来管理游戏中的各种元素,比如玩家板子、球和砖块等。另外,随机数生成的运用使得游戏具有了一定的随机性,增加了游戏的趣味性和挑战性。
这次实验不仅是对我编程能力的一次锻炼,也预示着我走向Python项目开发的关键起步。我相信在未来的学习和实践中,我会不断地完善和扩展自己的编程技能,为更多有趣的项目和挑战做好准备。这次实验不仅仅是一个结束,更是一个新的开始,我期待着未来在Python项目开发领域的更多探索和收获。

7. 课程总结

本学期的Python课程让我从头开始系统地学习了Python编程语言。课程内容涵盖了Python的基础语法、数据结构、函数、面向对象编程等方面,同时也涉及了一些常用的Python库和工具,如Pygame、BS和Crypto等。通过理论学习和实践编程项目,我对Python的特性和应用有了更深入的了解。
学习Python让我感受到了编程的乐趣和魅力。与C语言相比,Python的语法更加简洁和灵活,使得编程变得更加轻松和高效。我喜欢Python的语法清晰、易读易懂的特点,以及丰富的库和工具支持,这让我能够更快地实现自己的想法,并且享受到编程带来的成就感。
通过本学期的Python课程,我不仅学会了Python编程语言的基础知识,还提升了自己的编程能力和解决问题的能力。我接触了更为高级的python使用,如爬虫、游戏等。同时,我也学会了如何利用Python的库和工具来简化编程任务,提高编程效率。这我未来的学习非常有用。
同时,我建议Python课程需要适度增加同学们的代码编写任务量,布置一些有趣的代码任务,提升同学们的学习兴趣,增加学习印象。同时也可以引入小组分配制度,小组策划一个项目,在结课时进行验收。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值