引言
大家好,在平淡的编程日常学习中,我继C语言之后又学习了python语言,肯定会有人会问,这两种语言,哪个好学,哪个好用呢?就我个人学习的经历来说python好学,更具趣味性,同时它也好用,至少它上手应用快。
咳咳,回归正题,今天咱们就来讲讲,如何使用python语言来开发一个贪吃蛇小游戏!完整代码我放在了文章最后,需要的同学可以自己拿。
我将整个过程归纳为八个大点:
1.图片素材准备
2.导入模块
3.绘制界面
4.绘制贪吃蛇饲料
5.绘制贪吃蛇
6.游戏规则设计
7.打包
8.代码
一.图片素材准备
请自行准备两张图片素材,来作为游戏结束背景和游戏彩蛋图片。
比如下面这两张:


二.导入模块
在这里我主要讲以下三点:
1.如何导入模块
2.没有对应模块该如何下载
3.导入自定义模块的两种方法
(1)如何导入模块
语法:import +模块名
import pygame
(2)没有对应模块该如何下载
以我使用的pyCharm为例子:
1.首先要找到终端的功能点击它

图中被黄色标记的图标就是终端功能。
2.输入下载指令
下载的指令有两种选择
1.pip install 库名(模块名): 下载安装的是国外源⾥⾯的库 , 下载的会很慢 , 如果愿意等是没关系的
2.pip install 库名(模块名) -i 镜像源(国内的)
国内的镜像源地址:
清华⼤学 :https://pypi.tuna.tsinghua.edu.cn/simple/
阿⾥云:http://mirrors.aliyun.com/pypi/simple/
中国科学技术⼤学 :http://pypi.mirrors.ustc.edu.cn/simple/
华中科技⼤学:http://pypi.hustunique.com/
⾖瓣源:http://pypi.douban.com/simple/
腾讯源:http://mirrors.cloud.tencent.com/pypi/simple
华为镜像源:https://repo.huaweicloud.com/repository/pypi/simple
镜像源地址,起到的作用就像是连锁店一样,本来需要在国外的仓库里下载的东西,用了镜像源之后,就可以在国内仓库下载,这二者之间的距离想必大家应该清楚这节省了多少时间。
(3)导入自定义模块的方法
导入自定义模块又两种方法:
1.常规导入方式:
导入语法:
import 模块文件名
调用语法:
模块文件名.函数名(模块文件中你需要调用的函数名,是否需要参数看你是怎么写的函数)
例如:

2.对应调用模块函数方式:
导入语法:
from 模块文件名 import 函数名(模块文件中你需要调用的函数名,是否需要参数看你是怎么写的函数)
调用语法:
函数名(模块文件中你需要调用的函数名,是否需要参数看你是怎么写的函数)#可以直接调用函数
例如:

三.绘制界面
绘制界面我也分成几点:
1.初始化模块
2.创建游戏界面和标题
3.设置颜色(背景颜色,蛇的颜色,蛇饲料的颜色等)
4.图片文字处理
5.建立循环使游戏不断运行,不断刷新,以及退出设置。
(1).初始化模块
init(),用于初始化模块pygame的所有功能,而pygame,就是用于创建游戏方面的模块,接下来主要就是用它来完成游戏的创建。
(2).创建游戏界面和标题

(1280,720)这个参数哪里来的呢?这就要问set_mode()这个函数是干什么得了,它是用来创建游戏界面的,那我们的背景是不是要填满它?没错,需要,所以这里我们就直接用图片的大小(宽和高)参数来设置游戏界面的大小。
有人可能会问,(1280,720)的参数是怎么查看的其实很简单,鼠标右键点击文件夹中的图片,点击属性,选择详细信息,我们用的数据就是其中的分辨率。
(3).设置颜色

(255,252,22)这一串数据,就代表了一种颜色,那这一串数据怎么来的呢?也很简单,只要你找一个有截图功能的软件截图的时候就可以看到颜色数据,比如钉钉。

上面的三个数据会随着你的鼠标停留的目标变换而变换。
(4).图片文字处理

pygame.font.SysFont('华文行楷',50),'华文行楷'参数一,字体类别(name),50参数二,字体大小(size),作用是设置在游戏界面种打印出来的字体和字体大小。到时候可以作为参数引用,并且可以设置多种字体。
pygame.image.load('imge/snake_end.png'),是为了引用图片素材到程序中。
图中图片的路径是如何找出来的呢?其实很简单如果你的图片放在其他位置,可以直接用鼠标右键点击,然后选择复制文件地址,拿过来就行了:

“E:\\database\\code data\\python数据库\\python项目\\pythonProject1\\24.python-贪吃蛇大作战游戏-8月12日\\imge\\蛇.png ”,当然我建议文件地址复制过来之后像我一样多加一条斜杠,这是为了防止转义字符影响文件地址的使用,当然你也可以使用正斜杠“/”,这样就不会被影响了。
同样的如果你的文件就在项目里的话,你也可以,直接用鼠标右键点击图片文件,选择复制路径,在点击来自内容根的路径,在地址拿过来之后,修改一下只留下图片文件夹开头就行(前提是图片文件夹与调用文件处于同一目录下):


就像这样:“imge/snake_end.png”
有些时候,你觉得你的图片太大了不符合自己的心意或者游戏界面装不下,你就可以使用以下函数扩大或这缩小它:
# 扩大 end_photo=pygame.transform.scale(end_photo,(1280,720)) # 缩小 color_egg=pygame.transform.scale(color_egg,(500,400))
pygame.transform.scale(),参数一,更改目标,参数二,更改后数据(要变成多大多小)
扩大和缩小只看你填的参数大小,不过我不建议扩大很多,扩大并不会增加图片细节,只是将原有像素放大,所以图片会越来越模糊;而缩小是合并像素,会相对清晰
(5).建立循环

上图中:
# 事件设置 for event in pygame.event.get():#获得所有事件
什么是事件呢?其实事件就像是,程序中某个状态改变或者动作发生的标记,就像是交通信号灯,控制等待与同行,根据条件的触发,来给出对应的回答。而这里的pygame.event.get(),则代表获取电脑上所有发生的事件(键盘的输入或者鼠标点击哪里都算事件),通过for循环,将其放入event(名字可以自己取)中。
而我们想要设置一个退出的条件,就可以用事件来一一对比,我们所设置的条件是否触发,就比如pygame.QUIT,它就代表了窗口右上角的×,意思是×被鼠标点击。只要满足条件就可以进入当前if语句中。
pygame.quit()# 关闭所有窗口和功能 sys.exit()#退出程序
上面的内容我相信大家看注释也能看明白,不过我要提醒一点,如果想要sys.exit()生效,就需要引入对应模块。
import sys
当我们做完了以上步骤就可以运行程序看看效果了:

图中左上角就可以看到一行小字,这就是之前我们设置的标题,现在我们的窗口内是黑色的,当然这是它默认的颜色,和我们设置颜色并没有关系,接下来,我们就需要填充背景和绘制图文:

blit,参数一,绘制目标,参数二,绘制的位置(这个参数,其实是对应x,y坐标,以窗口从上往下为y,0-上限,以窗口从左到右为x,0-上限,绘制图片其实就和截图一样,都是有一个起点的,而这个坐标就是图片文字左上角的起点)
图中,我们运用if else语句简单写了一个判断游戏是否运行的语句,如果游戏正在运行,那么就填充背景,反之则绘制结束背景图。当然因为背景是黑色我们看不到变化,所以我们将game_over的False改为True,我们就可以直接看到结束背景图绘制的效果了:

四.绘制贪吃蛇饲料
绘制蛇饲料分为以下几步:
1.设置蛇饲料的参数
2.绘制蛇饲料
(1)设置蛇饲料的参数
首先,在设置蛇饲料参数之前,我们要先导入一个模块。

random模块,适用于生成伪随机数和执行随机化操作:
为什么是伪随机数?那首先我们要知道什么是随机数!不可预测的才是随机数,但是random它的随机数都是基于数学算法算出来的,只要知道参数,并且主动设置了种子(默认的是系统时间),那么结果就是可预测的,所以说它是伪随机数,但对于我们当前制作的小游戏来说,只要随机出来的数字不是明显可预测的就行,也就没有什么伪不伪的说法了。
什么是随机化操作?随机选择,随机打乱等,这些都是随机化操作
接下来,就是设置蛇饲料的参数:

random.randint(20,1200),取20-1200的随机数,为什么要除以10.0呢?因为蛇饲料的大小是10为单位,除以10.0,用round()取整在乘以10,就可以防止出现除了10的倍数之外的值。
(2)绘制蛇饲料
当我们准备好了参数后就可以使用函数来绘制了:

这里我们简单介绍一下pygame.draw.rect()这个函数的功能是用来画矩形的,参数分别是那些,table是背景颜色,food_color是蛇饲料的颜色,food_x,food_y,是蛇饲料在窗口中的位置坐标(x,y),food_size,设置的是长宽。
下面是达成的效果图:

五.绘制贪吃蛇
绘制贪吃蛇的步骤如下:
1.设置贪吃蛇需要用到的参数
2.绘制贪吃蛇
3.让贪吃蛇动起来
(1)设置贪吃蛇需要用到的参数

以上就是我们绘制一条贪吃蛇所需要的参数,他们分别起到了什么作用?大家可以通过注释了解。其中snake_body,我们使用的是列表,方便记录贪吃蛇的每个身体节点的位置。
(2)绘制贪吃蛇
当我们做好准备之后,可以开始绘制我们的贪吃蛇了:
pygame.draw.rect(table,snake_color,(x,y,snake_size,snake_size))
如果我们只想绘制贪吃蛇,只需要像绘制矩形一样绘制出贪吃蛇就行了,具体用法我们看上面绘制蛇饲料哪里就行,具体效果如下:

黄色矩形就是我们的贪吃蛇了。
(3)让贪吃蛇动起来
那如何让我们的贪吃蛇动起来呢?
首先我们得用之前我们设置好的snake_body列表,记录我们贪吃蛇的节点坐标也就是当前的蛇头的位置,我们可以写成snake_head[],然后将我们蛇头的坐标记录在其中:snake_head=[snake_x,snake_y],最后通过修改snake_x,snake_y的数值,在用for循环来循环绘制,达到移动的目的,但如果只是不断的绘制的话,最终只能绘制出一条直线,所以我们需要删掉修改前的旧节点。
以上写成代码:

运行视频:https://live.csdn.net/v/515836
https://live.csdn.net/v/515836
我们动起来还不够,我们需要能控制它上下左右的行动方向,这才是一条蛇而不是一个会平移的矩形,想要做到这一点,我们需要怎么做呢?首先通过键盘来控制贪吃蛇的移动方向,这属于是一种事件,而事件我们只需要在事件设置中写,具体代码如下:

if event.type==pygame.KEYDOWN:#获取键盘上的操作
通过这串代码,我们可以获得用户在键盘上的操作,你想获得哪个键的操作情况,就可以它下面具体是那个键,触发后又该有什么的效果,很简单不是吗?就像下面这样:
# 获取键盘上的操作
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_LEFT:#获取左键的情况是否触发
#如果触发左键,就执行以下语句
#左转
direction_x=-1
direction_y=0
我们的移动,其实就是将一个窗口划分程很多个小格子,然后将小格子作为坐标轴的单位,这样我们不管是蛇还是蛇饲料,它们的坐标就等于通过修改横竖小格子数量来控制移动,同理,我们也可以修改坐标来控制方向。
snake_x+=direction_x
snake_y+=direction_y
而这一步就是将我们的键盘与贪吃蛇正式链接起来,snake_x和snake_y是蛇头的坐标,换句话说,最新的一个坐标才是蛇头,通过修改它就可以控制贪吃蛇的行动方向。
运行视频:https://live.csdn.net/v/515854
https://live.csdn.net/v/515854
六.游戏规则设计
游戏规则主要针对以下几点:
(1)延时
(2)吃到蛇饲料
(3)出界
(4)吃到自己
(5)游戏时计分
(6)彩蛋出现条件
(7)自动加速
(1)延时
当我们运行游戏时,我们会发现贪吃蛇的移动速度貌似有点太快了,不好调试,当这种时候我们就需要有一个延时功能来帮助我们调试代码。
首先我们要导入时间相关模块:
import time
然后,在我们代码的倒数第二排写以下代码:
time.sleep(1 / 80)
最后……就没了,没错就这么简单
运行视频:https://live.csdn.net/v/515872
https://live.csdn.net/v/515872
(2)吃到蛇饲料
当我们的蛇动起来后,我们就得想办法让它吃东西,不然怎么叫贪吃蛇呢?顺便长身体。

if abs(snake_x-food_x)<snake_size and abs(snake_y-food_y)<snake_size:
abs()功能是返回绝对值,通过abs(snake_x-food_x)计算出的绝对值,我们就知道了蛇头距离蛇饲料的距离是否已经吃到了食物,不管贪吃蛇在蛇饲料左边还是右边,同理上下也可以知道,这样我们就可以判断出蛇是否吃到蛇饲料。
# 吃到了 food_x = round(random.randint(20, 1200) / 10.0) * 10.0 food_y = round(random.randint(20, 700) / 10.0) * 10.0 # 吃到食物的标记+1 snake_length+=1
吃到了,我们就需要更新蛇饲料的坐标,重新绘制一个蛇饲料,并且记录下我们吃到的次数。
# 如果蛇吃到食物,就会变长,反之则剪掉前一步
if len(snake_body) > snake_length:
del snake_body[0]
这一步就是为了保证每吃到一次食物,贪吃蛇就会多出一个节点,长一小段,也是为了防止无限拉长。
(3)出界
通过使用snake_x,snake_y,横竖的坐标来对比窗口的大小1280*720,来判断是否出界:

game_over=True
text=f.render('游戏结束,祝大家蛇年快乐!',True,font_color)
game_over=True,宣告游戏结束,text装的是文本,f.render,f指的是用之前设置好的字体,render即渲染,将准备好数据转化为可视化,也就是在屏幕上输出。
运行视频:https://live.csdn.net/v/516030
https://live.csdn.net/v/516030
(4)吃到自己
除了出界,吃到自己,或者说碰到自己身体的任何一部分都算游戏结束:

我实现这个功能整体的思想是,先遍历一遍贪吃蛇出蛇头外的所有的节点,然后与蛇头的坐标进行比对是否符合,来达到判断是否吃到自己的目的,我实现的比较粗略,但大致的功能也算是实现了,有兴趣的同学可以尝试着细化。
table.blit(text, (550, 50))
table.blit(图像,坐标),blit在pygame中是绘制图像的核心方法,全称“Bit Block Transfer”,也就是位块传输,,简单来说,blit就是贴图操作,在对应的位置贴上预设好的图片,文字的图像。
运行视频:https://live.csdn.net/v/516035
https://live.csdn.net/v/516035
(5)游戏时计分
一个游戏如果只是一条贪吃蛇在哪里不断的吃东西,那有什么意思,我们得知道它吃了多少,才能体现大家的技术高低不是😀,所以,我们得为每次吃下的食物计分,并且标明相关的文本。
首先想要在一个文本中控制分数自动变化,那就需要设置一个变量,保证分数变化,文本中的分数也要一起变化:

我们先添加变量score,用来记录分数。

然后在11点的部分中添加score+=10,意思是,每当贪吃蛇吃掉一颗蛇饲料就会获得10分。

我们可以看出,在这里我把蛇的坐标給移到了if语句中,意思是,当游戏开始时,贪吃蛇就可以不断移动,但游戏结束后就不会移动。
text=f.render(f"游戏运行中,目前分数:{score}",True,font_color)# 当游戏运行时创建,如果删除则不会创建,就找不到正在运行时需要的对应text
以上的代码,我前面我都讲过功能用法,这里我讲一下细节,{f"游戏运行中,目前分数:{score}"),这里的f是为了在文本中插入变量用的,这应该算是python语言的特色用法,为什么我会在这串代码后面写下这就注释呢?因为我将所有text所需要的blit,集中成了一排代码放在了最外层倒数第三排,不算注释的话,这样就减少了我们的代码量,虽然只减少了两句。


这样我们就将14,12,13中的blit给写成了一句,因为它们都是在不同情况下创建text。
运行视频:https://live.csdn.net/v/516222
https://live.csdn.net/v/516222
(6)彩蛋出现条件
我们游戏有时候也需要点彩蛋作为小奖励,当贪吃蛇成长到一定地步就会跳出来一张图片作为彩蛋,我们也不写太复杂的机制,我们就采用等差数列的规律来安排,每隔100分弹出一次。

这里我们首先同样是创建变量a作为计数器,在吃到蛇饲料时计数,并且通过if语句作为判断,并用and,提出了三个必须同时满足的条件,使彩蛋每增加100分的时候出现一次彩蛋,而我猜肯定有人会认为,下面这句代码是多余的。
if a==6:
a=0
这段代码在这里有三个作用:
1.重置计数器:让控制彩蛋显示的变量 a 不会无限增大;
2.终止彩蛋显示:通过重置 a 为 0,让 a>=1 的条件不成立,从而让彩蛋只短暂显示后消失;
3.支持循环触发:重置后,下次分数达到 100 的倍数时,彩蛋能再次触发显示。
运行视频:https://live.csdn.net/v/516223
https://live.csdn.net/v/516223
(7)自动加速
为什么在加了延迟的情况下,还要加自动加速呢?首先加延迟是因为贪吃蛇初始移动速度过快,我们需要延时才好操作,而加自动加速,则是因为贪吃蛇总不能一直维持在一个很慢的速度吧?
所以我们要增加自动加速的功能。我们自动加速的规则很简单和彩蛋出现的条件相同,只要增加100分就加一次速。

我们怎么做到加速这一步呢?很简单,还记得这一步吗?
snake_x+=direction_x snake_y+=direction_y
我们只需要将direction_x或者_y固定增加的值换成提前创建的变量add,就可以控制他贪吃蛇的移动速度。


七.打包
# file:3.打包.py # author:wangjing-0522 # specifics; # 1 安装打包库 # pip install pyinstaller -i https://pypi.tuna.tsinghua.edu.cn/simple # 2.转到对应项目目录 # cd 21.python-FishingJoygame-8月7日 # 3.输⼊打包命令 # pyinstaller -F -w 启动程序 关联程序注意-w是小写,间隔三格 # pyinstaller -F 启动程序 关联程序,间隔三格(如果没有终端窗口的话) # 启动程序表示你的主程序也就是代码的开始 # 如果有其他程序需要⼀起打包,需要使⽤关联程序,如果没有,可以忽略 # 如果只是单独的python代码,没有界⾯窗体的,建议去掉-w,因为会直接显示控制条,其实这⼀类打 # 包没有太⼤意义 # 4.观察打包结束后的⽂件夹,exe就在dist⽂件夹中 # 5.注意事项: # (1)解决办法: 将图⽚等资源⽂件放⼊dist中 # (2)最后打包2个⼀起发给好兄弟即可
八.代码
# file:贪吃蛇大作战小游戏.py
# author:wangjing_0522
# specifics;
import time
import pygame
import sys
import random
# 1.初始化模块
pygame.init()
# 2.创建游戏界面(1280,720)和标题
# 游戏界面
table=pygame.display.set_mode((1280,720))
# 游戏标题
pygame.display.set_caption("贪吃蛇蛇年大作战")
# 3.设置颜色
# 背景颜色
black_color=(0, 0, 0)
# 蛇的颜色
snake_color=(255,252,22)
# 蛇饲料颜色
food_color=(249,35,255)
# 字体颜色
font_color=(0,255,0)
# 4.图片文字处理
# 设置字体
f=pygame.font.SysFont('华文行楷',50)
f1=pygame.font.SysFont('华文行楷',20)
# 设置结束背景和彩蛋图片
end_photo=pygame.image.load('imge/snake_end.png')
color_egg=pygame.image.load('imge/蛇.png')
# 扩大
end_photo=pygame.transform.scale(end_photo,(1280,720))
# 缩小
color_egg=pygame.transform.scale(color_egg,(500,400))
# 6.蛇饲料的单个格子大小和初始位置
food_size=10
food_x=round(random.randint(20,1200)/10.0)*10.0
food_y=round(random.randint(20,700)/10.0)*10.0
# 8.蛇的位置坐标和大小
snake_size=10
snake_x=100
snake_y=200
# 9.蛇的后期大小,初始长度方便后期判断是否吃了蛇饲料
snake_body=[[snake_x,snake_y]]
snake_length=1
# 10.蛇的行进方向
direction_x=0
direction_y=0
# 5建立程序循环
game_over=False
score=0
a=0
add=5
while True:
# 根据游戏状态,不停绘制相应的游戏背景
if not game_over:
# fill,作用:填充颜色
table.fill(black_color)
else:
# blit,作用:将图片文字绘制到指定的位置
table.blit(end_photo,(0,0))
# 事件设置
for event in pygame.event.get():#获得所有事件
# 退出条件
if event.type==pygame.QUIT:
pygame.quit()# 关闭所有窗口和功能
sys.exit()#退出程序
# 获取键盘上的操作
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_LEFT:
direction_x = -add
direction_y = 0
if event.key == pygame.K_RIGHT:
direction_x = add
direction_y = 0
if event.key == pygame.K_UP:
direction_x = 0
direction_y = -add
if event.key == pygame.K_DOWN:
direction_x = 0
direction_y = add
# 14.蛇不管吃没吃到蛇饲料,一旦游戏开始,贪吃蛇就不停的移动,开始计分
if not game_over:
snake_x+=direction_x
snake_y+=direction_y
text=f.render(f"游戏运行中,目前分数:{score}",True,font_color)# 当游戏运行时创建,如果删除则不会创建,就找不到正在运行时需要的对应text
pygame.draw.rect(table, snake_color, (1100,680, snake_size, snake_size))
pygame.draw.rect(table, food_color, (1200,680, food_size, food_size))
text1=f1.render(":贪吃蛇",True,font_color)
text2=f1.render(":蛇饲料",True,font_color)
table.blit(text1,(1105,680))
table.blit(text2,(1205,680))
# 15.当彩蛋满足条件时就会弹出来
if score % 100 == 0 and score != 0 and a >= 1:
table.blit(color_egg,(300,300))
time.sleep(1/10)
a+=1
if a==6:
a=0
# 7.不停的绘制蛇和蛇饲料
snake_head=[snake_x,snake_y]
snake_body.append(snake_head)
# pygame.draw.rect(绘制到哪里,什么颜色,(x坐标,y坐标,宽,高)):画贪吃蛇 画矩形
for x,y in snake_body:
pygame.draw.rect(table,snake_color,(x,y,snake_size,snake_size))
pygame.draw.rect(table,food_color,(food_x,food_y,food_size,food_size))
# 11.判断蛇是否吃到蛇饲料
if abs(snake_x-food_x)<snake_size and abs(snake_y-food_y)<snake_size:
# 吃到了
food_x = round(random.randint(20, 1200) / 10.0) * 10.0
food_y = round(random.randint(20, 700) / 10.0) * 10.0
# 吃到蛇饲料的标记+1
snake_length+=1
# 计分
score+=10
a+=1
# 16.加速条件判断
if score % 100 == 0 and score != 0:
add += 2
# 如果蛇吃到食物,就会变长,反之则剪掉前一步
if len(snake_body) > snake_length:
del snake_body[0]
# 12.判断是否出界
if snake_x<0 or snake_x>=1280 or snake_y<0 or snake_y>=720:
game_over=True
text =f.render('游戏结束,祝大家蛇年快乐!',True,font_color)
# 13.判断是否吃到自己
for x,y in snake_body[:-1]:
if snake_x==x and snake_y==y:
game_over=True
text =f.render("游戏结束,祝大家蛇年快乐!", True, font_color)
table.blit(text, (550, 50))
time.sleep(1 / 20)
# 不断刷新界面
pygame.display.update()
完
转载自CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/wangjing_0522/article/details/150473434



