20254218 《Python程序设计》实验4报告
20254218 2025-2026-6 《Python程序设计》实验4报告
课程:《Python程序设计》
班级: 2542
姓名: 王兴聪
学号:20254218
实验教师:王志强
实验日期:2026年6月12日
必修/选修:专选课
一、实验要求
Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。
课代表和各小组负责人收集作业(源代码、视频、综合实践报告)
Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。
例如:编写从社交网络爬取数据,实现可视化舆情监控或者情感分析。
例如:利用公开数据集,开展图像分类、恶意软件检测等
例如:利用Python库,基于OCR技术实现自动化提取图片中数据,并填入excel中。
例如:爬取天气数据,实现自动化微信提醒
例如:利用爬虫,实现自动化下载网站视频、文件等。
例如:编写小游戏:坦克大战、贪吃蛇、扫雷等等
注:在Windows/Linux系统上使用VIM、PDB、IDLE、Pycharm等工具编程实现。
批阅:注意本次实验不算做实验总分,前三个实验每个实验15分,累计45分。本次实践算入综合实践,打分为45分。
评分标准:
(1)程序能运行,功能丰富(至少5个功能)。(需求提交源代码,并建议录制程序运行的视频)15分
(2)综合实践报告,要体现实验分析、设计、实现过程、结果等信息,格式规范,逻辑清晰,结构合理。20分。
(3)在实践报告中,需要对全课进行总结,并写课程感想体会、意见和建议等。10分
二、实验过程
1、程序选择:
在游戏选择之际,我想起了小学时候使用老年按键手机比较多,除了通电话之外,就只能玩一些小游戏,例如贪吃蛇、推箱子、小熊爬竹竿和飞机大战,原本想做贪吃蛇的,但感觉做的人挺多的,最终决定做一个新版的飞机大战。
2.游戏玩法设计
玩家通过键盘 ←/→ 或 A/D 控制屏幕底部的战机,自动连续发射子弹。在无限关卡中尽可能多地击落从顶部下落的敌机来获得分数(普通敌机+10分,红色精英敌机+20分)。玩家初始拥有3条生命,被敌机撞到会损失1条生命并短暂无敌。每获得150分,敌机下落速度加快、生成间隔缩短,同时屏幕边缘出现红色闪烁提示。游戏在生命归零时结束,显示最终得分和本地最高分,按 R 键可重新开始,按 P 键暂停。
3.代码编写
(1)安装pygame并初始化游戏环境
设计思路
游戏需要图形界面、键盘输入、碰撞检测等功能,因此选用 pygame 库。首先导入所需模块,初始化 pygame 引擎,创建 800×600 的游戏窗口,设置标题,并创建时钟对象控制帧率(60帧/秒)。

(2) 游戏状态与基础属性定义
游戏需要多种状态:菜单、进行中、暂停、结束。使用常量区分。
同时定义玩家、子弹、敌机的尺寸、颜色、速度等基础属性,便于后续调整。
使用 RGB 元组定义常用颜色,方便绘制图形。同时编写 draw_text() 函数,用于在屏幕上显示任意文字,支持居中/左对齐。


(3)最高分持久化存储
使用 json 文件保存本地最高分。程序启动时加载,游戏结束时若当前分数更高则覆盖。避免每次运行都从零开始。

(4)游戏难度
敌机速度与生成频率:普通敌机的下落速度从初始 3 开始,每获得 150 分增加 0.8,并用 限制上限;同时敌机的生成间隔从初始 60 帧每 150 分减少 3 帧。
视觉压迫感:在主循环的游戏状态 STATE_PLAYING 里,背景颜色根据得分逐渐变红;并且在得分刚超过 150 的整数倍时,屏幕中央会短暂显示红色文字“难度提升!”。
精英敌机:当得分达到 300 分且场上没有精英敌机时,自动生成一只需要两次命中才能摧毁的红色精英敌机,进一步增加挑战。


(5)精灵类设计(玩家、子弹、敌机)
所有游戏对象都继承 pygame.sprite.Sprite,便于统一管理和碰撞检测。
玩家:用蓝色方块表示,响应左右键移动,边界限制。
子弹:黄色长条,向上移动,超出屏幕消失。
普通敌机:灰色方块,向下移动。
精英敌机:红色方块,血量2,需要击中两次。

(6)碰撞检测与得分逻辑
使用 pygame.sprite.groupcollide() 检测子弹与敌机组的碰撞,子弹击中普通敌机即消失,得分+10;击中精英敌机则减少其血量,每次命中+5分,摧毁再+10分。
玩家与敌机的碰撞通过 spritecollide() 实现,碰撞后玩家生命-1,进入无敌状态(闪烁1秒),并清空碰撞的敌机。

(7)游戏主循环与状态机
主循环内部分为:事件处理 → 游戏逻辑更新(仅在 STATE_PLAYING 时)→ 绘制界面。
开始菜单:显示游戏标题、最高分、操作说明,按空格开始。
游戏中:自动射击、敌人生成、移动、碰撞、更新UI。
暂停:按 P 暂停,再按 P 恢复。
结束:生命归零时显示最终得分和最高分,按 R 重新开始。

(8)UI信息显示
使用 draw_text() 在屏幕上显示当前得分、生命值、最高分、难度提示等。得分和生命显示在左上角,最高分显示在右上角,暂停提示在底部角落。

(9)游戏重置函数
当玩家在游戏结束或暂停时按 R,需要将分数、生命、位置、敌机列表、难度参数等全部重置,恢复到初始状态。

(10)结束条件:玩家生命归零
游戏结束的触发条件是玩家生命值 player_health 变为 0。当玩家与敌机碰撞且不在无敌状态时,生命值减 1。减后若 player_health <= 0,则将游戏状态设置为 STATE_GAMEOVER,并检查是否需要更新最高分(若当前分数超过已有最高分则保存)。

4.源代码
import pygame
import random
import json
import os
初始化Pygame
pygame.init()
pygame.mixer.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, 50, 50)
GREEN = (50, 255, 50)
BLUE = (50, 100, 255)
YELLOW = (255, 255, 50)
GRAY = (100, 100, 100)
游戏时钟
clock = pygame.time.Clock()
FPS = 60
游戏状态
STATE_MENU = 0
STATE_PLAYING = 1
STATE_GAMEOVER = 2
STATE_PAUSE = 3
game_state = STATE_MENU
玩家属性
player_width = 50
player_height = 40
player_x = SCREEN_WIDTH // 2 - player_width // 2
player_y = SCREEN_HEIGHT - 80
player_speed = 7
player_health = 3
invincible_timer = 0 # 无敌倒计时(帧)
invincible_duration = 60 # 无敌1秒(60帧)
子弹属性
bullet_width = 5
bullet_height = 10
bullet_speed = -10
bullet_cooldown = 0
bullet_cooldown_max = 10 # 每10帧射一发(约0.167秒)
普通敌机属性
normal_enemy_width = 40
normal_enemy_height = 40
normal_enemy_speed = 3 # 初始速度,随分数增加
normal_enemy_spawn_delay = 60 # 初始60帧生成一个(1秒)
normal_enemy_spawn_counter = 0
精英敌机属性
elite_enemy_width = 50
elite_enemy_height = 50
elite_enemy_speed = 4
elite_enemy_health = 2
elite_enemy_spawn_score = 300 # 每300分才可能生成
elite_enemy_on_field = False
分数系统
score = 0
highscore = 0
highscore_file = "highscore.json"
动态难度基数
base_spawn_delay = 60 # 会随分数减少
base_normal_speed = 3
加载最高分
def load_highscore():
global highscore
if os.path.exists(highscore_file):
try:
with open(highscore_file, 'r') as f:
data = json.load(f)
highscore = data.get("highscore", 0)
except:
highscore = 0
else:
highscore = 0
def save_highscore():
with open(highscore_file, 'w') as f:
json.dump({"highscore": highscore}, f)
重置游戏变量
def reset_game():
global score, player_health, invincible_timer, normal_enemy_speed, normal_enemy_spawn_delay
global normal_enemy_spawn_counter, elite_enemy_on_field, bullet_cooldown, game_state
global player_x
score = 0
player_health = 3
invincible_timer = 0
player_x = SCREEN_WIDTH // 2 - player_width // 2
normal_enemy_speed = base_normal_speed
normal_enemy_spawn_delay = base_spawn_delay
normal_enemy_spawn_counter = 0
elite_enemy_on_field = False
bullet_cooldown = 0
# 清空所有精灵组
bullets.empty()
normal_enemies.empty()
elite_enemies.empty()
game_state = STATE_PLAYING
更新难度(根据分数)
def update_difficulty():
global normal_enemy_speed, normal_enemy_spawn_delay
# 每150分提高一次难度(速度上限8,生成间隔下限20帧≈0.33秒)
added_speed = (score // 150) * 0.8
new_speed = base_normal_speed + added_speed
normal_enemy_speed = min(8, new_speed)
生成间隔减少:初始60帧,每150分减少3帧,最低20帧
new_delay = base_spawn_delay - (score // 150) * 3
normal_enemy_spawn_delay = max(20, new_delay)
精灵类
class Player(pygame.sprite.Sprite):
def init(self):
super().init()
self.image = pygame.Surface((player_width, player_height))
self.image.fill(BLUE)
self.rect = self.image.get_rect()
self.rect.x = player_x
self.rect.y = player_y
self.mask = pygame.mask.from_surface(self.image)
def update(self):
global player_x
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] or keys[pygame.K_a]:
self.rect.x -= player_speed
if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
self.rect.x += player_speed
# 边界限制
if self.rect.left < 0:
self.rect.left = 0
if self.rect.right > SCREEN_WIDTH:
self.rect.right = SCREEN_WIDTH
player_x = self.rect.x
class Bullet(pygame.sprite.Sprite):
def init(self, x, y):
super().init()
self.image = pygame.Surface((bullet_width, bullet_height))
self.image.fill(YELLOW)
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.bottom = y
def update(self):
self.rect.y += bullet_speed
if self.rect.bottom < 0 or self.rect.top > SCREEN_HEIGHT:
self.kill()
class NormalEnemy(pygame.sprite.Sprite):
def init(self):
super().init()
self.image = pygame.Surface((normal_enemy_width, normal_enemy_height))
self.image.fill(GRAY)
self.rect = self.image.get_rect()
self.rect.x = random.randint(0, SCREEN_WIDTH - normal_enemy_width)
self.rect.y = -normal_enemy_height
def update(self):
self.rect.y += normal_enemy_speed
if self.rect.top > SCREEN_HEIGHT:
self.kill()
class EliteEnemy(pygame.sprite.Sprite):
def init(self):
super().init()
self.image = pygame.Surface((elite_enemy_width, elite_enemy_height))
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.x = random.randint(0, SCREEN_WIDTH - elite_enemy_width)
self.rect.y = -elite_enemy_height
self.health = elite_enemy_health
def update(self):
self.rect.y += elite_enemy_speed
if self.rect.top > SCREEN_HEIGHT:
self.kill()
创建精灵组
player = Player()
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
bullets = pygame.sprite.Group()
normal_enemies = pygame.sprite.Group()
elite_enemies = pygame.sprite.Group()
辅助函数:显示文字
def draw_text(text, size, x, y, color=WHITE, center=True):
font = pygame.font.Font(None, size)
surface = font.render(text, True, color)
rect = surface.get_rect()
if center:
rect.center = (x, y)
else:
rect.topleft = (x, y)
screen.blit(surface, rect)
主循环
load_highscore()
running = True
while running:
# 事件处理
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if game_state == STATE_MENU:
if event.key == pygame.K_SPACE:
reset_game()
elif game_state == STATE_PLAYING:
if event.key == pygame.K_p:
game_state = STATE_PAUSE
elif game_state == STATE_PAUSE:
if event.key == pygame.K_p:
game_state = STATE_PLAYING
elif event.key == pygame.K_r:
reset_game()
elif game_state == STATE_GAMEOVER:
if event.key == pygame.K_r:
reset_game()
game_state = STATE_PLAYING
游戏逻辑
if game_state == STATE_PLAYING:
# 无敌倒计时
if invincible_timer > 0:
invincible_timer -= 1
自动射击
if bullet_cooldown <= 0:
bullet = Bullet(player.rect.centerx, player.rect.top)
bullets.add(bullet)
all_sprites.add(bullet)
bullet_cooldown = bullet_cooldown_max
else:
bullet_cooldown -= 1
生成普通敌机
if normal_enemy_spawn_counter <= 0:
enemy = NormalEnemy()
normal_enemies.add(enemy)
all_sprites.add(enemy)
normal_enemy_spawn_counter = int(normal_enemy_spawn_delay)
else:
normal_enemy_spawn_counter -= 1
生成精英敌机(条件:分数 >= elite_spawn_score 且场上没有精英敌机)
if score >= elite_enemy_spawn_score and not elite_enemy_on_field:
elite = EliteEnemy()
elite_enemies.add(elite)
all_sprites.add(elite)
elite_enemy_on_field = True
更新所有精灵
player.update()
bullets.update()
normal_enemies.update()
elite_enemies.update()
子弹 vs 普通敌机碰撞
hits = pygame.sprite.groupcollide(bullets, normal_enemies, True, True)
for hit in hits:
score += 10
子弹 vs 精英敌机碰撞
for bullet in bullets:
hit_elites = pygame.sprite.spritecollide(bullet, elite_enemies, False)
for elite in hit_elites:
bullet.kill()
elite.health -= 1
score += 5 # 每次命中+5分
if elite.health <= 0:
elite.kill()
elite_enemy_on_field = False
score += 10 # 击毁额外+10分
玩家与普通敌机碰撞(无敌时无视)
if invincible_timer <= 0:
hits = pygame.sprite.spritecollide(player, normal_enemies, True)
if hits:
player_health -= 1
invincible_timer = invincible_duration
if player_health <= 0:
game_state = STATE_GAMEOVER
if score > highscore:
highscore = score
save_highscore()
玩家与精英敌机碰撞
if invincible_timer <= 0:
hits = pygame.sprite.spritecollide(player, elite_enemies, False)
if hits:
for elite in hits:
elite.kill()
elite_enemy_on_field = False
player_health -= 1
invincible_timer = invincible_duration
if player_health <= 0:
game_state = STATE_GAMEOVER
if score > highscore:
highscore = score
save_highscore()
动态难度调整
update_difficulty()
难度上升屏幕闪红提示(每获得150分时短暂闪烁,这里简化:每帧检测分数变化)
可选效果:显示红色警告文字
difficulty_warning = (score % 150 < 10 and score > 0) # 刚过150分倍数的短时间
背景颜色随得分变红(轻度)
bg_color = (min(255, 30 + score//15), 20, 20) if score>0 else BLACK
绘制部分
if game_state == STATE_MENU:
screen.fill(BLACK)
draw_text("星际守卫者", 64, SCREEN_WIDTH//2, SCREEN_HEIGHT//3, YELLOW)
draw_text("按 空格键 开始游戏", 30, SCREEN_WIDTH//2, SCREEN_HEIGHT//2, WHITE)
draw_text("←/→ 移动战机 | 自动射击 | 躲开敌机", 24, SCREEN_WIDTH//2, SCREEN_HEIGHT//2+80, GRAY)
draw_text("最高分: " + str(highscore), 28, SCREEN_WIDTH//2, SCREEN_HEIGHT//2+140, GREEN)
elif game_state == STATE_PLAYING:
# 背景色随分数变红
screen.fill(bg_color)
# 绘制所有精灵
all_sprites.draw(screen)
# 无敌闪烁效果
if invincible_timer > 0 and (invincible_timer // 5) % 2 == 0:
pygame.draw.rect(screen, WHITE, player.rect, 2)
# 显示UI
draw_text("得分: " + str(score), 30, 70, 20, WHITE, center=False)
draw_text("生命: " + str(player_health), 30, 70, 60, WHITE, center=False)
draw_text("最高分: " + str(highscore), 30, SCREEN_WIDTH-90, 20, GREEN, center=False)
# 难度提示
if score >= 150:
warning = (score // 150) * 150
if score - warning < 30: # 刚升级后短暂提示
draw_text("难度提升!", 36, SCREEN_WIDTH//2, 100, RED)
# 暂停提示
draw_text("按 P 暂停", 20, SCREEN_WIDTH-70, SCREEN_HEIGHT-20, GRAY, center=False)
elif game_state == STATE_PAUSE:
screen.fill(BLACK)
draw_text("暂停中", 64, SCREEN_WIDTH//2, SCREEN_HEIGHT//3, YELLOW)
draw_text("按 P 继续游戏", 30, SCREEN_WIDTH//2, SCREEN_HEIGHT//2, WHITE)
draw_text("按 R 重新开始", 30, SCREEN_WIDTH//2, SCREEN_HEIGHT//2+60, GRAY)
elif game_state == STATE_GAMEOVER:
screen.fill(BLACK)
draw_text("GAME OVER", 64, SCREEN_WIDTH//2, SCREEN_HEIGHT//3, RED)
draw_text("最终得分: " + str(score), 36, SCREEN_WIDTH//2, SCREEN_HEIGHT//2, WHITE)
draw_text("最高分: " + str(highscore), 36, SCREEN_WIDTH//2, SCREEN_HEIGHT//2+50, GREEN)
draw_text("按 R 键重新开始", 30, SCREEN_WIDTH//2, SCREEN_HEIGHT//2+130, GRAY)
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
5.运行视频
https://www.bilibili.com/video/BV1pujN68Erh/?spm_id_from=333.1007.top_right_bar_window_dynamic.content.click&vd_source=3b3693ccffcfd01b8cdcec974f5b00a9
三、实验中遇到的困难和解决方法
1.游戏窗口闪退或运行时报错“pygame.error: video system not initialized”,可能是 pygame.quit() 被提前调用,或者代码中存在语法错误导致程序异常退出,窗口一闪而过看不见错误信息。
解决方法:
(1)在代码末尾(pygame.quit() 之前)加上 input() 或 pygame.time.wait(3000) 让窗口停留。
(2) 使用命令行运行脚本(而非直接双击),这样错误信息会保留在终端中。
2.游戏运行时按键(如移动、暂停)没有反应,中文输入法下,按键事件可能被输入法拦截,pygame 无法捕获 KEYDOWN 事件。另外也可能是事件循环被阻塞或按键检测代码位置错误。
解决方法:
(1) 按 Shift 或 Ctrl+空格 将系统输入法切换为英文模式。
(2)在事件循环中添加 print(event) 调试,确认是否收到了 KEYDOWN 事件。
四、实验总结
哈哈,我终于搞完了!一开始看到这个实验要求,什么爬虫、机器学习、神经网络,这些高大上的名词我说实在话我感觉我根本做不来,感觉只有做一些小游戏稍微简单一点,挑来挑去,最终决定做个飞机大战,在大模型的辅助下成功把这个小游戏做了出来。
首先是装pygame,一开始还是让大模型手把手教我装pygame,然后就是我学会了用pygame这个库来写游戏。从创建窗口、画图形,到让物品掉落、检测碰撞,每一步都让我对Python的实际应用有了更深的理解。
下一步就是解决代码的问题,我构思了游戏设计的大概,然后让AI帮我加入更多的玩法和小细节,同时就是开始写代码和调教代码。后面当蓝色的小飞机真的能左右移动,子弹biubiubiu打爆敌机的时候,还是挺有成就感的。虽然画面很简陋,就是用方块拼的,但毕竟是自己一点一点调出来的。最高分还能存下来,每次破纪录都挺爽。
不过这次实验也让我意识到做个游戏出来还是不太容易的,既要考虑到游戏的合理性,又要考虑到游戏体验感对玩家来说是好是坏,兼顾下来还是不容易,起码我做的这个游戏我没有感觉到百分百顺手,但我也感觉我做的挺好的了,实现了这个游戏能够运转,过程是值得的!
六、课程综合总结和心得体会
1.在Python这门课的学习中我学到了很多。
首先是Python的一些基本知识和原理,例如自定义函数,循环语句等。还记得第一节课编写最简单的程序时,我因为程序报错而感到手足无措,最后才发现是运用了中文冒号的缘故。而现在,经过了这么多节课程的学习,我已经可以熟练编写一些简单的程序,例如剪刀石头布和猜数字小游戏。这进一步锻炼了我的实践能力和知识水平,让我接触到了之前作为一名文科生从未探索过的领域,也让我发现了Python的乐趣。在开始时我对Python了解得很少,仅仅局限于高中的信息技术课本上。这也让我在最初的学习中感到有些吃力,有时候被老师提问也答不太上来。我很感谢老师用心的教导,每节课都把相关知识点讲得很清楚,提问后也会带领我们进一步复习巩固,帮助我们不断学习新的知识、收获新的成功,让我们受益匪浅。在这一学习的过程中,我的思维和习惯也得到了很好的培养。Python的学习培养了我的理科思维。让我学着借助数据和实验来认识问题和解决问题,从已知条件出发,借助逻辑推理和数据分析来得到自己想要的结果。同时这也培养了我细心细致的习惯,从最开始的总是遗忘诸如标点符号一类的细节而导致程序不断报错,到现在的细致编写每一行代码、基本做到不在基础性细节上犯错,我变得更加认真严谨。同时,在那一次次的遇到挫折并尝试着解决问题的过程中,我学着迎难而上、越挫越勇,而在面对着诸多困难完成最后这个实验之后,回望这一学期的Python学习课程,那种成就感和满足感是难以言表的。还有一个很重要的收获就是学会摆脱对大数据的依赖。ai工具的确方便,但我们不能因此过度依靠ai,更需要注重自己的思考与行动,自己去探索、自己去学习、自己去实践,如此方能有所收获。正如老师在最后一节课上所言,“那些看似波澜不惊的日复一日,终将在某天,让我们看到坚持的意义。”未来的大学生活和Python的学习都是如此,只有通过不断的努力,才能获得成功。“功不唐捐,玉汝于成”,在未来的学习中,我也将继续运用了解Python知识,将理论融于实践,进一步求索。
2.意见和建议:前面的基础知识比较容易理解,但是后面就都比较难了,比如用socket函数编制服务器和客户端的那个实验,当初就不是特别理解,老师以后讲的时候可以稍微放慢一点速度!还有有时候老师编写代码的速度比较快,感觉有点跟不上,建议老师稍微停留几秒或者提醒大家记一下重点步骤。
对于文科生来说Python的学习难度确实很大,感觉光听课还是不够的,老师可以在课前几天发布预习内容让大家提早学习一下下节课要讲的重点内容,也可以推荐一些相关的资料,这样应该可以帮助同学们在课堂上跟上进度!最后,老师讲得特别好,人也特别幽默搞笑,时不时丢两张图片或者视频还有聊天记录在群里面就跑了,更搞笑了,也给课程带来了更多的笑料,老师继续努力。

浙公网安备 33010602011771号