20212306实验四 Python综合实践
课程:《Python程序设计》
班级: 2123
姓名: 张阳
学号:20212306
实验教师:王志强
实验日期:2022年5月20日
必修/选修: 公选课
一学期的python课程落下帷幕,在王志强老师的指导下,我也算是对python有了一定的了解。但是相较于有一定编程基础的同学来说,我的水平也就只是刚入门的级别。这次综合实践的选题我选择了编写贪吃蛇小游戏,虽然这个游戏可能对其他的同学很简单,但是对于我来说,还是具有一定挑战性,因此我花费了一些时间和精力,尽我所能完成了我所能达到的层次。在此分享一下我的思考过程和总结反思。
编写代码时的心路历程
我们首先可以将屏幕分成若干个等面积小块,以便后面更容易理解分析。
主要需要解决的两个点
1.如何让蛇“走”起来————跟随
后面一个格子跑到前面一个格子,一个一个代替。后一个格子跟着前一个格子走,头跟着控制器的方向走。
2.怎么将食物吃到肚子里————吃的过程
如果蛇头和食物重合,就需要将该格子与蛇头合并,并且在尾部增加一格。
相关思路的技术解决
pygame
专门做游戏的一个库,帮助绘制图形,捕捉事件,帮助联网,帮助连接游戏控制器。
Pygame三大对象
·Pygame.display 显示
·Pygame.time 掌管时间
·Pygame.event事件相关(比如说用户点了一下,用户把游戏关了)
整体思路框架
构建框架→绘制场景→绘制蛇头、食物→移动蛇头→绘制蛇身→吃到食物
构建框架
对框架本身进行初始化,然后决定画面大小。
pygame.init()
size元组,宽高,显示出来窗口
W = 800
H = 600
size = (W, H)
显示和绘图相关
pygame.display
此时运行有两个问题,窗口没有标题,且只存在一瞬间。
那么该怎么解决呢?
设置标题我们可以采用
set_caption
pygame.display.set_caption('贪吃蛇')
为了不让他只存在一瞬间,我们需要实现游戏的循环。
While一直循环下去,但是不能一直循环下去,用户选择退出时应该不绑架人家,允许人家退出游戏。准备一个变量quit。
进行时间控制
clock=pygame
设置一个帧频,帧频的作用是什么呢,大概是可以控制你的蛇跑的快慢吧。
clock.tick(x)
clock.tick(20)
处理事件
1.游戏退出问题
处理事件队列
pygame.event.get() p
在event内部处理各种事情
Quit=False,就可以做游戏的收尾工作了
但是还是会退出,那么现在就需要渲染。
pygame.display渲染 flip让出控制权,把控制权交给系统进行渲染,各种各样的工作
pygame.display.flip()
画图
pygame.draw.rect
需要考虑画的小方块和方块的颜色。
pygame.draw.rect(
window, color,
(left, top, cell_width, cell_height)
)
绘制场景
场景到底长什么样子?
每个格子可以是蛇头,蛇身,也可以是蛇的食物。我们看到的是移动的蛇头,和食物,但在计算机里呈现的就是二维数组。
!!!搞清楚:格子体现出来,怎么画出来格子
将格子体现出来:
row=100有多少行格子有多少列格子
因为有了屏幕的长和宽,所以通过除法,潜在的得到了每个格子有多大
画格子:
Point对象,每个格子都能用坐标的形式表现出来,更加直观清晰,直接定义每个东西所在位置
class Point:
row = 0
col = 0
def __init__(self, row, col):
self.row = row
self.col = col
def copy(self):
return Point(row=self.row, col=self.col)
绘制蛇头
开始定义蛇头,初始位置区在中间(同时需要考虑到如果格子横向数目为奇数的情况)
head = Point(row=int(ROW / 2), col=int(COL / 2))
定义食物的位置
def gen_food():
while 1:
pos = Point(row=random.randint(0, ROW - 1), col=random.randint(0, COL - 1))
虽然定义了,但是我们需要给他们画出来。
根据据上方的距离和据一侧的距离实现定位。
Left=所在的列每个格子有多宽 top是所在的行每个格子的高
rect函数
draw开始画画,颜色、位置、长宽高
可以通过上述内容进行蛇头和食物的绘制。
移动蛇头
如果朝左移动,row不动,col动。其他方向同理。
if direct == 'left':
head.col -= 1
elif direct == 'right':
head.col += 1
elif direct == 'up':
head.row -= 1
elif direct == 'down':
head.row += 1
此时蛇头已经可以开始移动,但是会发现蛇头根本不受我的键盘控制,那么怎么通过上下左右键来控制蛇的移动方向呢?
很容易想到,通过“事件”event来解决。
pygame.KEYDOWM与键盘进行“沟通”.将各个键分别定义成上下左右,实现我用键盘来控制蛇的方向,不让他失控。但是此时呢,蛇头会从食物里盲目的穿过去,先别担心,一步一步来,我们现在已经实现了蛇头的移动。
绘制蛇身
现在我们来思考一下,如何绘制蛇的身子?
我们有各种各样的方法来绘制,比如说可以采取表格的方式一个一个表示,但很显然,这不是最简单的方式。
我们可以把蛇的身子存成一个列表,如何去用列表实现蛇身呢?
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit = False
elif event.type == pygame.KEYDOWN:
if event.key == 273 or event.key == 119:
if direct == 'left' or direct == 'right':
direct = 'up'
elif event.key == 274 or event.key == 115:
if direct == 'left' or direct == 'right':
direct = 'down'
elif event.key == 276 or event.key == 97:
if direct == 'up' or direct == 'down':
direct = 'left'
elif event.key == 275 or event.key == 100:
if direct == 'up' or direct == 'down':
direct = 'right'
在移动的过程当中,只需要做一件事,把原来的头插到前面,把原来的尾巴给删掉。
先处理身子,因为原来的头的位置是需要的。
1.把原来的头插入到snakes的头上
snakes.insert(0, head.copy())
2.把snakes的最后一个删掉
snakes.pop()
3.记得绘制蛇的身子,不然依旧只有蛇头
食物随机出现,被吃
随机很容易
random
def gen_food():
while 1:
pos = Point(row=random.randint(0, ROW - 1), col=random.randint(0, COL - 1))
#
is_coll = False
那么怎么吃掉东西呢?(也就是,食物在接触蛇头后消失,而不是蛇穿过食物)
很简单,只要蛇头和食物的行列都一样,那么就吃掉了。等下,以为这就结束了?并不是,吃掉食物蛇当然要长大。再写好几行来实现增长一节蛇的长度吗?不用,只需要不删除就行。
eat = (head.row == food.row and head.col == food.col)
if not eat:
snakes.pop()
但是实践发现,蛇是长长了,但是食物并没有消失
于是此时就要让食物在新的位置出现。
if eat:
food = gen_food()
此时,还有游戏已经大致完成,但是还是有一些小bug
一些小bug——游戏的简单完善
比如说,食物生成完全随机,它有没有可能生成在蛇的身子上。再者说,如果蛇撞到了墙是不是就需要让游戏结束?这都是初步完善需要考虑的问题。
1.食物生成
用函数表示,随机生成几个坐标然后检测一下是否和蛇碰上了,如果碰上了就需要重新生成。
如果和脑袋碰上,直接检测。
如果和身子碰上,记得要写循环。
生成食物,统一用函数来生成,避免潜在碰撞问题
def gen_food():
while 1:
pos = Point(row=random.randint(0, ROW - 1), col=random.randint(0, COL - 1))
#
is_coll = False
# 是否跟蛇碰上了
if head.row == pos.row and head.col == pos.col:
is_coll = True
# 蛇身子
for snake in snakes:
if snake.row == pos.row and snake.col == pos.col:
is_coll = True
break
if not is_coll:
break
2.关于撞墙和撞到自己
撞墙:如果他的列已经小于零,或者列小于零,或者他的列大于等于总列数,或者行大于等于总行数,说明他要挂了。
撞自己:如果列和行等于蛇的列和行。
dead = False
# 1.撞墙
if head.col < 0 or head.row < 0 or head.col >= COL or head.row >= ROW:
dead = True
# 2.撞自己
for snake in snakes:
if head.col == snake.col and head.row == snake.row:
dead = True
break
3.如果死掉了
就显示游戏结束,并且自动退出程序
if dead:
print('死了')
quit = False
综合实践总结
综合实践到此就已经结束了,这次代码编写的过程中让我不仅对整个学期的学习内容有了很好的复习、总结和应用,还让我自主学习到了更多的python的技能 ,虽然这个贪吃蛇小游戏现在仍有很多的不足有待完善,我相信通过日后的学习精进,掌握更多知识后,我将会这个小游戏进一步完善。
在华为云服务器上运行
源代码
class Point:
row=0
col=0
def __init__(self, row, col):
self.row=row
self.col=col
def copy(self):
return Point(row=self.row, col=self.col)
#初始框架
import pygame
import random
#初始化
pygame.init()
W=800
H=600
ROW=30
COL=40
size=(W,H)
window=pygame.display.set_mode(size)
pygame.display.set_caption('贪吃蛇')
bg_color=(255,255,255)
snake_color=(200,200,200)
head=Point(row=int(ROW/2), col=int(COL/2))
head_color=(0,128,128)
snakes=[
Point(row=head.row, col=head.col+1),
Point(row=head.row, col=head.col+2),
Point(row=head.row, col=head.col+3)
]
#生成食物
def gen_food():
while 1:
pos=Point(row=random.randint(0,ROW-1), col=random.randint(0,COL-1))
#
is_coll=False
#是否跟蛇碰上了
if head.row==pos.row and head.col==pos.col:
is_coll=True
#蛇身子
for snake in snakes:
if snake.row==pos.row and snake.col==pos.col:
is_coll=True
break
if not is_coll:
break
return pos
#定义坐标
food=gen_food()
food_color=(255,255,0)
direct='left' #left,right,up,down
#
def rect(point, color):
cell_width=W/COL
cell_height=H/ROW
left=point.col*cell_width
top=point.row*cell_height
pygame.draw.rect(
window, color,
(left, top, cell_width, cell_height)
)
pass
#游戏循环
quit=True
clock=pygame.time.Clock()
while quit:
#处理事件
for event in pygame.event.get():
if event.type==pygame.QUIT:
quit=False
elif event.type==pygame.KEYDOWN:
if event.key==273 or event.key==119:
if direct=='left' or direct=='right':
direct='up'
elif event.key==274 or event.key==115:
if direct == 'left' or direct == 'right':
direct='down'
elif event.key==276 or event.key==97:
if direct == 'up' or direct == 'down':
direct='left'
elif event.key==275 or event.key==100:
if direct == 'up' or direct == 'down':
direct='right'
#吃东西
eat=(head.row==food.row and head.col==food.col)
#重新产生食物
if eat:
food = gen_food()
#处理身子
#1.把原来的头,插入到snakes的头上
snakes.insert(0, head.copy())
#2.把snakes的最后一个删掉
if not eat:
snakes.pop()
#移动
if direct=='left':
head.col-=1
elif direct=='right':
head.col+=1
elif direct=='up':
head.row-=1
elif direct=='down':
head.row+=1
#检测
dead=False
#1.撞墙
if head.col<0 or head.row<0 or head.col>=COL or head.row>=ROW:
dead=True
#2.撞自己
for snake in snakes:
if head.col==snake.col and head.row==snake.row:
dead=True
break
if dead:
print('死了')
quit=False
#渲染——画出来
#背景
pygame.draw.rect(window, bg_color, (0,0,W,H))
#蛇头
for snake in snakes:
rect(snake, snake_color)
rect(head, head_color)
rect(food, food_color)
#
pygame.display.flip()
#设置帧频
clock.tick(20)
实验中遇到的困难
问题1.写代码的时候会遇到很多困难的地方
解决:去CSDN上参考别人的代码,对比发现自己的代码问题在哪里以及是否可以写的更简单。去b站参考一些视频。
问题2:无法在华为云服务器上运行python程序
解决:这一部分真的花了好长好长的时间,从如何把python2的默认版本到改换成python3 ,如何下pygame应用,因为写的是小游戏需要可视化,又花了很久的时间去研究如何用xming在putty中将游戏界面调出。其中遇到了很多很多困难,一度有过想放弃的念头,但是在课代表和学长学姐的帮助下,以及自己不断地搜搜搜,问问问,终于实现了在华为云服务器上的成功运行!在此还是十分感谢课代表不离不弃的指导!!!
全课进行总结,课程感想体会、意见和建议
⭐经过这一学期学习,我了解了Python的语言基础、流程控制语句、有关字符串的操作、文件操作、正则表达式、网络爬虫、Socket编程、Python操作数据库等等。在老师的讲解与指导下,我初步入门了python,并激发起了学习python的热情 。虽然经历了一个学期的python课程学习,但受限于个人水平,我仍有许许多多的知识需要进一步了解,并反复练习加以巩固。同时,课程给我带来的还有自学的能力,老师在课堂上虽然讲了很多内容,但是有更多的内容是需要我们课后进一步学习,深入研究的。俗话说“师傅领进门,修行靠个人”,老师为我们勾画出了python的具体框架,更多的需要靠我们自己摸索,通过不断地巩固和深入学习,把基础筑的更牢,把大厦建的更高。python是一门使用广泛的高效率的编程语言,学好这门语言更有利于我们以后代码编写、大创研究等项目,但是光靠这一学期的课程明显是不够的,在以后的日子里,我也会继续保持学习热情,坚持python的学习。
⭐另外,还特别喜欢王志强老师的讲课方式,循循渐进,和蔼可亲。在讲知识点的同时进行实践操作,这一点会帮助我们更直观更高效的学习。同时,王老师在讲课的时候也会具体指出如果怎么怎么写,代码就会出现什么样的错误,这一点让我们对错误的写法有了更深刻的认识,大大减少了以后犯错的情况。
⭐十分十分感谢王志强老师这一个学期给我们带来的课程讲解,希望还有机会能在课堂上聆听您的教诲!
⭐我也会在以后的日子里,以不息为体,以日新为道,对知识始终保有最积极的态度和最大的热情。