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 坐标在
0
到screen_width - brick_width
之间,步长为brick_width + brick_padding
- y 坐标在
0
到screen_height // 2
之间,步长为brick_heigh + brick_padding
- x 坐标在
-
使用
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. 实验结果
游戏视频:
打砖块
开始界面:
游戏界面:
结束界面:
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课程需要适度增加同学们的代码编写任务量,布置一些有趣的代码任务,提升同学们的学习兴趣,增加学习印象。同时也可以引入小组分配制度,小组策划一个项目,在结课时进行验收。