20244210 2024-2025-2 实验四Python综合实践
课程:《Python程序设计》
班级: 2442
姓名: 陈可
学号:20244210
实验教师:王志强
实验日期:2025年5月31日
必修/选修: 专选课
一、实验要求
Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。
课代表和各小组负责人收集作业(源代码、视频、综合实践报告)
Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。
例如:编写从社交网络爬取数据,实现可视化舆情监控或者情感分析。
例如:利用公开数据集,开展图像分类、恶意软件检测等
例如:利用Python库,基于OCR技术实现自动化提取图片中数据,并填入excel中。
例如:爬取天气数据,实现自动化微信提醒
例如:利用爬虫,实现自动化下载网站视频、文件等。
例如:编写小游戏:坦克大战、贪吃蛇、扫雷等等
批阅:注意本次实验不算做实验总分,前三个实验每个实验15分,累计45分。本次实践算入综合实践,打分为45分。
评分标准:
(1)程序能运行,功能丰富。(需求提交源代码,并建议录制程序运行的视频)15分
(2)综合实践报告,要体现实验分析、设计、实现过程、结果等信息,格式规范,逻辑清晰,结构合理。20分。
(3)在实践报告中,需要对全课进行总结,并写课程感想体会、意见和建议等。10分
二、实验过程
1.程序选择:
鉴于本人小时候就对贪吃蛇游戏这种简单易上手但又时刻需保持高度注意力的游戏着迷,又在学习Python语言的过程中,逐步掌握了变量定义、函数编写、类的使用等,所以此次结课作业我选择编写贪吃蛇小游戏,基于自己的兴趣与知识,并拔高一层,上网搜索相关知识与讲解,一定程度上挑战自己,在python学习上更进一步。
2.游戏玩法设计:
游戏开始后,屏幕上会出现一条小蛇和5个食物。玩家通过键盘上的上、下、左、右键来控制蛇的移动方向。蛇在移动过程中如果吃到食物,身体就会变长,同时玩家会获得相应的分数。游戏的目标是尽可能多地吃到食物,让蛇不断变长,获得更高的分数。但如果蛇碰到屏幕边界或者自己的身体,游戏就会结束,此时玩家可以选择按下空格键重新开始游戏,或者按下ESC键退出游戏。
3.代码编写
(1)安装pygame:
在python软件包中搜索pygame并安装。

(2)导入模块:
pygame是用于开发游戏的库,提供了图形绘制、事件响应等功能;random用于生成随机数,在游戏中用于随机生成食物的位置;
sys 用于处理Python程序与系统的交互,比如在游戏结束时退出程序。

(3)初始化游戏:
通过pygame.init()初始化pygame库的所有模块,为后续的使用做准备;
通过clock=pygame.time.Clock()创建一个时钟对象,控制游戏的帧率,使游戏画面更新更加稳定。

(4)游戏参数定义:
分别用SCREEN_WIDTH和SCREEN_HEIGHT定义游戏窗口的宽度和高度为800像素和600像素;
通过GRID_SIZE定义游戏中的网格大小为20像素,使得游戏中的蛇、食物等元素以网格为单位进行定位和移动;
GRID_WIDTH和GRID_HEIGHT通过将窗口的宽、高度分别除以网格大小,计算出水平和垂直方向的网格数量,确定游戏元素在屏幕上的位置范围。

(5)颜色定义:
采用rgb颜色模型,分别定义游戏元素中将要用到的白色、黑色、红色、绿色。

(6)创建游戏窗口:
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) 根据之前定义的窗口宽度和高度,创建一个游戏窗口对象,并将其赋值给 screen 变量;
pygame.display.set_caption("贪吃蛇游戏") 设置游戏窗口的标题栏显示为“贪吃蛇游戏”,增强游戏的辨识度。

(7)初始化字体:
pygame.font.init()初始化pygame的字体模块,为使用字体功能做准备;
font = pygame.font.SysFont('simhei', 36)创建一个字号为36的“黑体(simhei)”字体对象,用于显示游戏中的主要提示信息,如游戏结束时的提示语;
small_font = pygame.font.SysFont('simhei', 24)创建一个字号为24的“黑体”字体对象,用于显示较小的文字信息,如游戏中的分数、次要提示等。

(8)定义snake类表示贪吃蛇:
a.用__init__ 构造类,在创建蛇对象时自动调用;
self.positions列表用于存储蛇身体各个部分所在的网格位置,初始时蛇头位于屏幕中间网格;
self.direction元组表示蛇当前的移动方向,初始设置为向右(水平方向移动1个单位,垂直方向移动0个单位);
self.color指定蛇的颜色为之前定义的绿色;self.length 设置蛇的初始长度为1。

b.设置移动方法:首先获取蛇头当前位置head,计算出移动后的新位置 new_head;
检查是否撞墙:新位置是否超出游戏窗口的网格边界(水平或垂直方向超出范围),若超出则返回False,表示游戏结束;
检查是否撞到自己身体:新位置是否与蛇身体其他部分重合,若重合也返回 False;
若上述条件都不满足,则将新位置插入到self.positions列表开头,表示蛇头移动到新位置,再根据蛇的当前长度判断是否需要删除列表末尾的位置(即蛇尾),以保持蛇身长度正确,最后返回True表示移动成功。

c.改变蛇的移动方向:接收一个新方向new_dir作为参数,通过判断新方向与当前方向是否相反(防止蛇瞬间掉头),若不相反则更新蛇的移动方向。

d.蛇身增长方法:吃到一个食物后蛇身增长一节

e.绘制蛇的外观:self.positions列表储存蛇身每个部位的网络坐标,for循环从中依次取出每个坐标。针对每个取出的坐标,首先通过pygame.draw.rect(screen, self.color, (pos[0] * GRID_SIZE, pos[1] * GRID_SIZE, GRID_SIZE, GRID_SIZE))绘制蛇身主体——screen指定绘制目标为游戏窗口;self.color将蛇身颜色(如绿色)作为矩形填充色;(pos[0] * GRID_SIZE, pos[1] * GRID_SIZE)把网格坐标转换为像素坐标,确定绘制位置;(GRID_SIZE, GRID_SIZE)设定矩形宽高,即单个蛇身网格尺寸。通过循环遍历,完成蛇身主体所有部分的绘制。
随后,再次使用pygame.draw.rect(screen, BLACK, (pos[0] * GRID_SIZE, pos[1] * GRID_SIZE, GRID_SIZE, GRID_SIZE), 1)为蛇身添加边框。与绘制主体相比,填充色改为BLACK黑色,同时通过参数1设置边框宽度为1像素。循环执行过程中,每个蛇身主体矩形外均生成黑色轮廓,增强蛇身辨识度,使蛇在游戏窗口中的呈现效果更加清晰。

(9)定义食物类:
a.类似于定义snake类,用__init__构造函数,创建食物对象时调用;
self.position 用于存储食物所在的网格位置,初始设为 (0, 0),随后通过调用 self.generate_position()方法随机生成实际位置;
self.color指定食物的颜色为之前定义的红色RED,使其在画面中醒目易见。

b.利用random模块的randint函数,在游戏窗口内随机生成事物的横纵坐标,以确定食物在游戏画面中的随机位置,增强不确定性趣味性。

c.绘制食物:同样类似于蛇的绘制,先用pygame.draw.rect函数绘制一个填充色为食物颜色self.color的矩形,表示食物本体。再绘制一个边框颜色为黑色 BLACK、宽度为1像素的矩形,为食物添加边框,使其在游戏窗口中清晰呈现。

(10)设计游戏结束的显示界面:
show_game_over_screen函数用于在游戏结束时展示相应界面。当game_over参数为True时触发执行:首先创建一个与游戏窗口大小相同的半透明黑色覆盖层overlay,通过设置pygame.SRCALPHA模式使其具有透明效果,并填充颜色(0, 0, 0, 180)(前三个值为RGB颜色,最后一个值180表示透明度),然后将该覆盖层绘制到游戏窗口screen上,营造出游戏结束的氛围;接着使用之前定义的字体对象font和small_font分别渲染游戏结束提示文字、重新开始提示文字和退出游戏提示文字,并设置相应的颜色;再通过 get_rect 方法获取每个文字对象的矩形区域,并设置其在屏幕上的居中位置;最后使用screen.blit方法将这些文字绘制到游戏窗口指定位置,完成游戏结束界面的展示。

(11)主函数:
a.首先创建一个蛇对象 snake,作为游戏中的主角;接着使用列表推导式创建包含5个食物对象的列表foods,为游戏初始化多个食物;game_over变量用于标记游戏是否结束,初始值设为False;score变量用于记录玩家在游戏过程中获得的分数,初始值为0。

b.主循环:游戏主循环while True确保游戏持续运行。在循环内部,通过 pygame.event.get() 获取所有游戏事件:当检测到pygame.QUIT 事件(即用户点击窗口关闭按钮)时,调用pygame.quit()释放pygame库资源,再调用sys.exit()安全退出程序;当检测到pygame.KEYDOWN事件用户按下键盘按键)时,若按下的是上、下、左、右键,通过dir_map字典将按键映射为对应的方向元组,并调用蛇对象的change_direction方法改变蛇的移动方向;若按下空格键且游戏已结束(game_over为True),则重新创建蛇对象和食物列表,重置游戏状态为初始值,准备重新开始;若按下ESC键且游戏已结束,同样调用pygame.quit()和sys.exit()退出游戏。

c.游戏画面渲染:
清空屏幕:screen.fill(BLACK)用黑色背景覆盖上一帧画面,避免残留图像。
绘制游戏元素:遍历foods列表,调用food.draw()绘制所有食物,调用snake.draw()绘制蛇的身体。
显示分数:用small_font渲染分数文本(如“分数: 30”),颜色为白色。
通过 screen.blit 将文本绘制在屏幕左上角(坐标(10,10))。

d.游戏更新状态与碰撞检测:
蛇的移动与死亡判定:调用snake.move()方法移动蛇身,该方法返回布尔值表示移动是否成功——若撞墙或撞到自身(not moved),将game_over标记设为True触发游戏结束;正常移动时,蛇头坐标会更新到新位置,蛇尾坐标被移除(保持长度不变)
食物检测与得分计算:获取蛇头坐标head = snake.positions[0]后,遍历所有食物,当蛇头与食物坐标重合(head == food.position)时:调用snake.grow()增加蛇身长度、生成新食物foods[i] = Food()、玩家得分score增加10分、执行break跳出循环。

e.游戏状态显示:根据 game_over 状态显示对应界面。若为True,显示“游戏结束”界面(如提示文字、重启按钮);若 False,则显示正常游戏界面。

f.画面刷新与性能控制:通过pygame.display.flip()刷新屏幕,显示最新绘制内容;通过clock.tick(10)限制帧率为10帧/秒,保证游戏节奏稳定。

g.程序入口:当脚本作为主程序运行时才启动游戏。如果该文件被其他模块导入,代码不会自动执行。

4.源代码
import pygame
import random
import sys
# 初始化游戏
pygame.init()
clock = pygame.time.Clock()
# 游戏参数
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
GRID_SIZE = 20
GRID_WIDTH = SCREEN_WIDTH // GRID_SIZE
GRID_HEIGHT = SCREEN_HEIGHT // GRID_SIZE
# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("贪吃蛇游戏")
# 字体初始化
pygame.font.init()
font = pygame.font.SysFont('simhei', 36)
small_font = pygame.font.SysFont('simhei', 24)
#定义蛇类
class Snake:
def __init__(self):
self.positions = [(GRID_WIDTH // 2, GRID_HEIGHT // 2)]
self.direction = (1, 0)
self.color = GREEN
self.length = 1
def move(self):
head = self.positions[0]
new_head = (head[0] + self.direction[0], head[1] + self.direction[1])
if (new_head[0] < 0 or new_head[0] >= GRID_WIDTH or
new_head[1] < 0 or new_head[1] >= GRID_HEIGHT):
return False
if new_head in self.positions:
return False
self.positions.insert(0, new_head)
if len(self.positions) > self.length:
self.positions.pop()
return True
def change_direction(self, new_dir):
if (new_dir[0] * -1, new_dir[1] * -1) != self.direction:
self.direction = new_dir
def grow(self):
self.length += 1
def draw(self):
for pos in self.positions:
pygame.draw.rect(screen, self.color,
(pos[0] * GRID_SIZE, pos[1] * GRID_SIZE,
GRID_SIZE, GRID_SIZE))
pygame.draw.rect(screen, BLACK,
(pos[0] * GRID_SIZE, pos[1] * GRID_SIZE,
GRID_SIZE, GRID_SIZE), 1)
class Food:
def __init__(self):
self.position = (0, 0)
self.color = RED
self.generate_position()
def generate_position(self):
self.position = (random.randint(0, GRID_WIDTH - 1),
random.randint(0, GRID_HEIGHT - 1))
def draw(self):
pygame.draw.rect(screen, self.color,
(self.position[0] * GRID_SIZE, self.position[1] * GRID_SIZE,
GRID_SIZE, GRID_SIZE))
pygame.draw.rect(screen, BLACK,
(self.position[0] * GRID_SIZE, self.position[1] * GRID_SIZE,
GRID_SIZE, GRID_SIZE), 1)
def show_game_over_screen(game_over):
if game_over:
overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 180))
screen.blit(overlay, (0, 0))
game_over_text = font.render("嘻嘻,没有控制好吧", True, (255, 215, 0))
restart_text = small_font.render("点击空格 重新开始", True, WHITE)
exit_text = small_font.render("按 ESC 退出游戏", True, WHITE)
text_rect = game_over_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 - 30))
restart_rect = restart_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 10))
exit_rect = exit_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 40))
screen.blit(game_over_text, text_rect)
screen.blit(restart_text, restart_rect)
screen.blit(exit_text, exit_rect)
def main():
snake = Snake()
foods = [Food() for _ in range(5)]
game_over = False
score = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key in [pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT]:
dir_map = {
pygame.K_UP: (0, -1),
pygame.K_DOWN: (0, 1),
pygame.K_LEFT: (-1, 0),
pygame.K_RIGHT: (1, 0)
}
snake.change_direction(dir_map[event.key])
if event.key == pygame.K_SPACE and game_over:
snake = Snake()
foods = [Food() for _ in range(5)]
game_over = False
score = 0
if event.key == pygame.K_ESCAPE and game_over:
pygame.quit()
sys.exit()
screen.fill(BLACK)
for food in foods:
food.draw()
snake.draw()
score_text = small_font.render(f"分数: {score}", True, WHITE)
screen.blit(score_text, (10, 10))
if not game_over:
moved = snake.move()
if not moved:
game_over = True
head = snake.positions[0]
for i, food in enumerate(foods):
if head == food.position:
snake.grow()
foods[i] = Food()
score += 10
break
show_game_over_screen(game_over)
pygame.display.flip()
clock.tick(10)
if __name__ == "__main__":
main()
5.运行视频
三、实验过程中遇到的问题和解决过程
·问题1:最开始上网搜索pygame的下载方法,想要在控制面板中输入“pip install pygame”下载,但得到“‘pip’不是内部或外部命令,也不是可运行的程序或批处理文件”的反馈,若想通过此方法装pygame,需要先重装pycharm。
·问题1解决方案:询问装上的同学,得知只需在pycharm内部的python软件包中搜索即可安装。
·问题2:蛇的移动速度过快。
·问题2解决方案:利用pygame的时钟对象来控制游戏帧率,进而控制蛇的移动速度。我设置了clock.tick(10),可以让游戏每秒运行10帧,使蛇的移动速度更合理。
·问题3:蛇180°大转弯碰到自己。
·问题3解决方案:在change_direction方法中添加方向冲突检测,阻止蛇180°转弯。
·问题4:分数提示、输了之后应显示的“嘻嘻,没控制好吧”与重来、退出等相关提示,均显示成了小方格而非具体文字内容。
·问题4解决方案:问题出在原本在字体初始化中将字体设置了none,误以为这样会显示系统默认字体,后来将其改为'simhei',即黑体。
·问题5:不知道怎样将设置除了白色之外的其他颜色。
·问题5解决方案:通过设置rgb值实现文字不同颜色的显示。
四、参考资料
《零基础学python》、哔哩哔哩、小红书
五、课程总结、感悟
零基础学python让我实现了python语言的入门,从最初认识到它的强大,到逐渐掌握了数据类型、变量命名、条件语句、循环语句等流程控制语句、序列、函数、面向对象等等知识,老师带着我们从理论到实践,一步步战胜恐惧,编写了石头剪刀布、note book 、socket等各种程序,学到知识与编写完成着实带给人不少成就感!印象深刻的是socket程序的编写,老师用最形象的电话比喻引入,最初不懂得其背后的逻辑,通过听讲、搜索、询问老师同学等方式,解决了包括IP地址等一系列错误,最终弄懂背后的原因,当和同学建立一起通话的那一刻,我感受到的不只是成功完成任务带来的喜悦,更有进一步思考这门语言背后的逻辑与思维方式的求知欲。很多看似复杂的问题其实可以条条分缕析拆解成一个个小步骤,而这些小步骤都来源于我们的基础知识,这不仅仅是python背后最基本的原理,更给我们的生活带来启示。同时,编程中对代码层级结构的严格要求,也让我意识到宏观规划与细节把控同样重要,只有理清逻辑脉络,才能高效达成目标。
Python 课程学习结束了,但是我想它带给我们方式的启发,以及对这门课程的兴趣将持续影响我们的日常生活。特别感谢王老师的悉心指导!特别感谢耐心专业的王老师,对知识点的系统梳理、生动有趣的讲解方式,让晦涩的概念变得通俗易懂。尤其是针对文科生的学习特点,老师巧妙设计案例,用“蛋炒饭”与“盖浇饭”类比面向过程和面向对象编程,用“电话通信”解释socket原理,这些形象的比喻不仅化解了我的畏难情绪,更让知识入脑入心。课堂上老师的热情满满、我们共同对python世界的探索、完成程序编写时收获的成就感,都让我对编程产生了兴趣。
六、意见建议
1.本学期的英语打卡环节让我受益匪浅,不仅积累了编程相关的专业词汇,更为备考四级打下基础,希望能延续这一学习方式。
2.建议老师未来多采用类比讲解,用生活实例帮助我们理解抽象概念(蛋炒饭盖浇饭),尤其对编程基础薄弱的同学而言,这种方式能极大提升学习兴趣与效率。
3.最后,希望王老师带着大家手把手敲代码是可以慢一些,增加关键步骤的停顿讲解。有时候我们会跟不上~
Python课程的结束不是终点,而是探索编程世界的新起点。这份学习经历赋予我的思维方法、解决问题的勇气,以及对编程的兴趣,都将持续影响我的学习与生活。衷心感谢王老师的教导,结课时的暖心建议与祝福都让人非常感动!我会珍藏于心,带着这份力量继续前行!!!
浙公网安备 33010602011771号