应无所住,而生其心
排名
1
文章
870
粉丝
112
评论
163
net core webapi post传递参数
庸人 : 确实坑哈,我也是下班好了好几次,发现后台传递对象是可以的,但...
百度编辑器自定义模板
庸人 : 我建议换个编辑器,因为现在百度富文本已经停止维护了,用tinymec...
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术

python游戏开发库pygame。pygame实现贪吃蛇

9046人阅读 2022/7/25 14:06 总访问:5407726 评论:0 收藏:0 手机
分类: Python

pygame介绍

Pygame 是一个专门用来开发游戏的 Python 模块,主要为开发、设计 2D 电子游戏而生,它是一个免费、开源的第三方软件包,支持多种操作系统,具有良好的跨平台性(比如 Windows、Linux、Mac 等)。Pygame 是 Pete Shinners 在 SDL(Simple DirectMedia Layer,一套开源的跨平台多媒体开发库)基础上开发而来,其目的是取代 PySDL。


截止到 2020 年 10 月 28 日,Pygame 已经诞生 20 周年。

SDL 是一套开放源代码的跨平台多媒体开发库,使用 C语言编写,它提供了多种控制图像、声音、输入/输出的函数,Pygame 可以看做是对 SDL 的封装,在 SDL 库基础上提供了各种 Python 的 API接口。目前 SDL 主要用于多媒体领域,比如开发游戏、模拟器、媒体播放器等。

通过 Pygame 我们能够创建各种各样的游戏和多媒体程序,但相比于开发大型 3D 游戏来说,它更擅长与开发 2D 游戏,比如扫雷、纸牌游戏、贪吃蛇、超级马里奥、飞机大战等,如果是 3D 游戏,可以选择一些功能更为全面的 Python 游戏开发库,比如 Panda3D(迪士尼开发的3D游戏引擎),PyOgre(Ogre 3D渲染引擎)等。

Python 作为一门解释型语言并不适合开发大型的 3D 游戏,但 Python 通过对其他语言的接口封装,使自身具备了开发大型 3D 游戏的能力,例如 Panda3D 的底层是用 C++ 语言编写的。一些较为知名的 3D 游戏,比如魔兽世界、文明帝国4、战地风云2,这些游戏都是使用 Python 语言开发的,而国内较为知名的“阴阳师”手游,也是由 Python 语言开发而成。

Pygame 官方网站(https://www.pygame.org/tags/all)提供许多丰富的游戏案例,它们全部使用 Pygame 开发

pygame安装

  1. pip install pygame

安装完成后使用命令查看版本

  1. python -m pygame --version

或者,输入:python -m pygame.examples.aliens,若能弹出游戏页面,则安装成功

python的常用对象

  1. pygame.display 显示
  2. pygame.time 时间
  3. pygame.event 事件
  4. pygame.draw 绘制

pygame实现贪吃蛇

一:能打开游戏窗体,点击x退出

  1. ## 引入所需要的模块
  2. import sys
  3. import pygame
  4. ## 使用pygame之前必须初始化
  5. pygame.init()
  6. ## 定义一个宽高
  7. width = 800
  8. height = 600
  9. size = (width,height)
  10. # 设置主屏窗口大小
  11. screen = pygame.display.set_mode(size)
  12. # 设置窗口的标题,即游戏名称
  13. pygame.display.set_caption('hello world')
  14. # 固定代码段,实现点击"X"号退出界面的功能,几乎所有的pygame都会使用该段代码
  15. while True:
  16. # 循环获取事件,监听事件状态
  17. for event in pygame.event.get():
  18. # 判断用户是否点了"X"关闭按钮,并执行if代码段
  19. if event.type == pygame.QUIT:
  20. #卸载所有模块
  21. pygame.quit()
  22. #终止程序,确保退出程序
  23. sys.exit()
  24. pygame.display.flip() #更新屏幕内容

默认就是一个黑色的窗体:

二:可以设置一下帧率,降低一下循环刷新的频率

不设置的话它是没有间隔的一直刷新

  1. ## 获取pygame的Clock对象
  2. clock = pygame.time.Clock()
  3. while True:
  4. for event in pygame.event.get():
  5. if event.type == pygame.QUIT:
  6. pygame.quit()
  7. sys.exit()
  8. pygame.display.flip()
  9. ## 设置一下帧率
  10. clock.tick(60)

三:绘制背景,让窗体变成白色背景


绘制背景,让窗体变成白色背景。其实就是画一个矩形覆盖整个窗体即可。其实就一句话

pygame.draw.rect(screen,(255,255,255),(0,0,width,height))

  • 参数1:需要绘制到的窗体对象
  • 参数2:绘制的颜色
  • 参数3:矩形的坐标,左上坐标-长-宽

主要代码如下:

  1. # 设置主屏窗口大小
  2. screen = pygame.display.set_mode(size)
  3. while True:
  4. for event in pygame.event.get():
  5. if event.type == pygame.QUIT:
  6. pygame.quit()
  7. sys.exit()
  8. ## 绘制背景,让窗体变成白色背景。其实就是画一个矩形覆盖整个窗体即可
  9. pygame.draw.rect(screen,(255,255,255),(0,0,width,height))
  10. pygame.display.flip()
  11. clock.tick(60)

四:绘制格子,也就是绘制蛇身,食物等


贪吃蛇的地图很简单,我们可以看成一个一个的格子,比如蛇身是一个一个的格子,食物也是一个一个的格子,障碍物也可以是一个一个的格子。格子的多少也就是地图可以操控空间有多少。

绘制一个任意大小的格子,其实也是使用draw.rect方法比如绘制一个正方形格子

  1. ## 绘制一个起始坐标点为0,0,宽度为50的正方形
  2. pygame.draw.rect(screen,(226, 163, 29),(0,0,50,50))


如果想要长一点,修改一下长宽即可,如下

  1. ## 绘制一个起始坐标点为0,0,宽度为130,高度为30的矩形
  2. pygame.draw.rect(screen,(226, 163, 29),(0,0,130,30))

颜色选取的话,可以参考这个网站
https://htmlcolorcodes.com/zh/yanse-xuanze-qi/

上面我们是直接写死位置以及写死高宽的,实际情况下,这些都应该动态计算得来。我们先动态的画出来定义任意位置的格子

比如我定义地图的宽度是600*400,最开始也是定义了的

  1. ## 定义地图的宽度是600*400
  2. width = 600
  3. height = 400

我们定义地图的行列数是10*15,注意为了保证我们我们每个格子是一个正方形,我们行列数要按照同一个比例来。当然如果你的游戏格子不是正方形可以不管这个。

  1. ## 定义地图的行列数是10*15
  2. row = 10
  3. col = 15

比如我们蛇头的位置是在5行7列,或者修改成其他任意合理的参数,怎么根据这些变量画出来蛇头的位置呢

  1. ## 定义蛇头的位置
  2. snake_head_row = 5
  3. snake_head_col = 7

其实很简单,首先蛇头所在格子的宽高,就是等于每个格子的宽度,我们先计算出来

  1. ## 格子的高度 = 地图的高度/行数
  2. boxheight = height/row
  3. ## 格子的宽度 = 地图的高度/列数
  4. boxwidth = width/col

然后宽高有了,就是起始的位置坐标了,也很简单。左边的距离就是列等于列宽所在列,距离上边的位置=行高所在行。然后画出来即可

  1. ## 格子的高度 = 地图的高度/行数
  2. boxheight = height/row
  3. ## 格子的宽度 = 地图的高度/列数
  4. boxwidth = width/col
  5. ## 定义蛇头的位置
  6. snake_head_row = 5
  7. snake_head_col = 7
  8. ## 距离左边的位置=列宽*所在列
  9. snake_head_left = snake_head_col*boxwidth
  10. ## 距离上边的位置=行高*所在行
  11. snake_head_top = snake_head_row * boxheight
  12. ## 根据定义的行列位置画出来格子所在的位置
  13. pygame.draw.rect(screen,(226, 163, 29),(snake_head_left,snake_head_top,boxwidth,boxheight))

蛇头位置定义在第5行,第7列的效果如下:

蛇头位置定义在5行,0列的位置如下:

完全没有问题,现在我们就可以动态的根据行列来了。

封装一个类表示格子的位置

上面格子的位置,也就是所在的行列,很多元素都需要使用到它,为了重复使用,也为了方便管理,最好封装一下,比如封装成一个类,更方便操作一点。很简单的一个类,就一个行列属性,然后一个初始方法用于赋值。

  1. ## 定义一个类表示格式的位置
  2. class Point:
  3. row = 0
  4. col = 0
  5. def __init__(self,row,col) :
  6. self.row = row
  7. self.col = col

然后蛇头的位置我们就可以这样定义,比如定义一个大概中间的位置

  1. ## 定义蛇头的坐标位置
  2. head = Point(int(row/2),int(col/2))

计算位置的时候,就可以使用对象的方式

  1. ## 距离左边的位置=列宽*所在列
  2. snake_head_left = head.col*boxwidth
  3. ## 距离上边的位置=行高*所在行
  4. snake_head_top = head.row * boxheight
  5. ## 根据定义的行列位置画出来格子所在的位置
  6. pygame.draw.rect(screen,(226, 163, 29),(snake_head_left,snake_head_top,boxwidth,boxheight))

封装一个画格子的方法

因为画格子也是一个需要重复使用的方法,所以我们需要封装一下。方法也很简单就是把前面写的计算格子宽高,根据格子行列计算距离左边与上边的距离等提到一个方法中。其实计算格子宽高的可以单独提出来写,我们暂时把这个放到这里吧。


方法有两个参数一个是坐标也就是格子所在的行列,还有一个是颜色

  1. def drawRect(point,color):
  2. ## 格子的高度 = 地图的高度/行数
  3. boxheight = height/row
  4. ## 格子的宽度 = 地图的高度/列数
  5. boxwidth = width/col
  6. ## 距离左边的位置=列宽*所在列
  7. box_head_left = point.col*boxwidth
  8. ## 距离上边的位置=行高*所在行
  9. box_head_top = point.row * boxheight
  10. ## 根据定义的行列位置画出来格子所在的位置
  11. pygame.draw.rect(screen,color,(box_head_left,box_head_top,boxwidth,boxheight))

现在我们要画格子就可以直接调用方法了。(蛇的颜色最好单独定义一个变量,后面要换成的时候随时可以换,这里为了演示没有使用变量)

  1. ## 调用封装方法绘制蛇身
  2. drawRect(headPoint,(226, 163, 29))

现在如果我们要在画一个其他元素,比如食物,就非常简单了,定义一下食物出现的位置和颜色,在调用一次方法就行。核心代码如下:

  1. ## 定义食物格子的位置
  2. foodPoint = Point(3,3)
  3. ## 定义一个食物格子的颜色
  4. foodColor = (226, 64, 29)
  5. ## 调用封装方法绘制食物
  6. drawRect(foodPoint,foodColor)

五:控制蛇的移动

让蛇可以自己移动

要让蛇移动非常简单,比如要让蛇左边这一步其实就是移动一格,就是让蛇头的位置让左边移动一格,也就是让蛇头的对象的列让左边-1就行了。向右移动就是让列+1,同理上下移动就是对行的加减。

先定义一个默认移动的方向,比如向左边吧。

  1. snakeDirect = "left"

然后封装一个蛇移动的方法

  1. ## 封装一个蛇移动的方法
  2. def snakeRun(snakeDirect):
  3. ## 向左边移动就是让列减去1即可。其他同理
  4. if snakeDirect == "left":
  5. headPoint.col -=1
  6. if snakeDirect == "right":
  7. headPoint.col +=1
  8. if snakeDirect == "up":
  9. headPoint.row -=1
  10. if snakeDirect == "down":
  11. headPoint.row +=1

然后在主循环里边调用一下即可

  1. while True:
  2. for event in pygame.event.get():
  3. if event.type == pygame.QUIT:
  4. pygame.quit()
  5. sys.exit()
  6. ## 让地图是白色背景
  7. pygame.draw.rect(screen,(255,255,255),(0,0,width,height))
  8. ## ----------------调用蛇移动的方法-----------------
  9. snakeRun(snakeDirect)
  10. ## 调用封装方法绘制蛇身
  11. drawRect(headPoint,snakeColor)
  12. ## 调用封装方法绘制食物
  13. drawRect(foodPoint,foodColor)
  14. #更新屏幕内容
  15. pygame.display.flip()
  16. ## 设置一下帧率
  17. clock.tick(5)

然后我们就可以看到蛇头的移动了。注意帧率哦,上面修改成5做测试了,如果是以前这种的60就会移动得非常快。60对于贪吃蛇这个游戏来吃帧率太高了-。-根本操作不过来。但是帧率的控制如果太低了,看着会很卡

控制蛇的方向

很简单,监听按键事件,然后根据按键改变移动的方向即可。比如wsad对应上下左右

  1. for event in pygame.event.get():
  2. if event.type == pygame.QUIT:
  3. pygame.quit()
  4. sys.exit()
  5. ## 监听按键事件
  6. if event.type == pygame.KEYDOWN:
  7. if event.key == 119:
  8. snakeDirect = "up"
  9. if event.key == 115:
  10. snakeDirect = "down"
  11. if event.key == 97:
  12. snakeDirect = "left"
  13. if event.key == 100:
  14. snakeDirect = "right"
  15. print(event)
  16. print(snakeDirect)

对应的key可以print输出看就行了

效果如下:

六:绘制蛇身

就是让蛇的格子多一点而已,其实也非常简单,可以用一个对象集合来表示蛇身。

  1. ## 定义一个蛇身的集合
  2. snakeBody = [
  3. Point(row=headPoint.row,col=headPoint.col+1),
  4. Point(row=headPoint.row,col=headPoint.col+2),
  5. Point(row=headPoint.row,col=headPoint.col+3),
  6. ]
  7. ## 随便定义一个蛇身的颜色
  8. snakeBodyColor = (200,200,200)

然后在主循环里边绘制出来,就是循环调用封装的方法而已。

  1. ## 蛇身绘制出来
  2. for item in snakeBody:
  3. drawRect(item,snakeBodyColor)

让蛇身跟着蛇头动。其实也非常简单,蛇身的移动就是两步。
第1步就是让蛇身向前一步,也就是前面蛇头的位置,代码表示就是向蛇身的集合里边添加一条记录而已

  1. ## 蛇身添加一条记录,也就是向前走一步,向蛇头位置走一步
  2. snakeBody.insert(0,Point(headPoint.row,headPoint.col))

第2步就是把蛇尾最后一格去掉,直接pop方法搞定

  1. 去掉蛇尾
  2. snakeBody.pop()

效果如下:

当然如果我们不区分蛇头与蛇身可以全部使用一个list表示即可。

七:随机产生食物与吃食物

随机产生食物使用一个随机数就行

  1. import random
  2. foodPoint = Point(random.randint(1,row-2),random.randint(1,row-2))

判断是否吃到了食物,只需要判断蛇头和食物重叠就行,如果重叠了说明吃到了食物。而判断是否重叠只需要判断蛇头的行列是否与食物的行列相同。

  1. ## 蛇头和食物重叠说明吃到了食物
  2. if headPoint.row == foodPoint.row and headPoint.col == foodPoint.col:
  3. ## 重新产生食物
  4. foodPoint = Point(random.randint(0,row-1),random.randint(0,row-1))
  5. else:
  6. ##没有吃掉食物才去掉蛇尾
  7. snakeBody.pop()

八:封装产生食物的方法,防止随机产生的食物与蛇身重叠了

我们产生食物的时候要判断一下,是否和蛇头,蛇身重叠了,如果重叠了要重新产生一次。封装的方式有很多种,下面是我封装的一种。

  1. def createFood(_headPoint,_snakeBody):
  2. while True:
  3. rfoodPoint = Point(random.randint(1,row-2),random.randint(1,row-2))
  4. isRepater = False
  5. ## 判断食物是否与蛇头重叠
  6. if _headPoint.row == rfoodPoint.row and _headPoint.col == rfoodPoint.col:
  7. isRepater=True
  8. continue
  9. ## 判断食物是否与蛇身重叠
  10. for item in _snakeBody:
  11. if item.col == rfoodPoint.col and item.row == rfoodPoint.row:
  12. isRepater=True
  13. continue
  14. ## 都没有碰上说明这次产生的食物是正常的可以正常返回
  15. if isRepater == False:
  16. return rfoodPoint

然后产生食物的地方都可以使用这个方法了,初始化食物的时候

  1. foodPoint = createFood(headPoint,snakeBody)

吃了食物后的时候:

  1. ## 蛇头和食物重叠说明吃到了食物
  2. if headPoint.row == foodPoint.row and headPoint.col == foodPoint.col:
  3. ## 重新产生食物
  4. foodPoint = createFood(headPoint,snakeBody)
  5. ##foodPoint = Point(random.randint(1,row-2),random.randint(1,row-2))
  6. else:
  7. ##没有吃掉食物才去掉蛇尾
  8. snakeBody.pop()

九:游戏结束检查,game over

贪吃蛇的游戏结束检查很简单,基本就是两点,一个是撞墙死了,一个是撞自己死了。当然规则自己定嘛,也可以撞自己不用死。判断也是非常简单,如下

  1. ## 游戏是否结束
  2. isdead = False
  3. ## 装边界死了
  4. if headPoint.row<0 or headPoint.row>=row or headPoint.col<0 or headPoint.col>=col:
  5. print("装边界死了")
  6. isdead = True
  7. ## 撞自己死了
  8. for body in snakeBody:
  9. if headPoint.row == body.row and headPoint.col == body.col:
  10. print("撞自己死了")
  11. isdead=True
  12. ## 最简单的处理,直接退出游戏
  13. if isdead == True:
  14. break
  15. ## 蛇身添加一条记录,也就是向前走一步,向蛇头位置走一步
  16. snakeBody.insert(0,Point(headPoint.row,headPoint.col))
  17. ## ----------------蛇的移动-----------------
  18. snakeRun(snakeDirect)

我们这里处理游戏结束非常简单,直接退出游戏了。应该还是要有点动画效果,至少也有个game over的展示界面撒,还能再次开始什么的。下次再说了。

未完待续….


欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739。有需要软件开发,或者学习软件技术的朋友可以和我联系~(Q:815170684)

评价

python学习 1-安装

Ptyhon非常简单易用的面向对象的脚本语言,跨平台 入门简单python分2个版本 Python2、Python3。Python 2.7 将于 2020 年结...

python学习 2-基本语法

基础:python脚本语言,不需要编译(像C#、Java、PHP、C++需要编译成机器可识别的语言), 而直接由解释器解释,很多地方类似...

python学习 3-爬虫基本介绍 及简单实例

爬虫爬虫就是一只猪,蜘蛛。。 网络蜘蛛。互联网是一个网由各个网站组成。无数的蜘蛛就在网上到处爬,根据网址从一个网站爬...

python实例 1-日志抓取处理 补错(附日志小技巧)

有时候数据出了问题,可以从日志中恢复数据(如果你没记日志..没备份..→_→..)一、日志展示介绍个平常自己用的小方法,如...

python实例 2-12306抢票(一) 登陆

开坑年关将近,终于对12306下手了,,平安夜撸代码,攻克了12306的登陆 2018-12-24 22:16:00没错 这篇博客就写从零开始的异...

python安装pip以及使用pip安装requests等模块

pip很简单的介绍pip 是一个现代的,通用的 Python 包管理工具。提供了对 Python 包的查找、下载、安装、卸载的功能。如果想...

python数据集合区别

列表(list):可读写,值可以重复,有序排列,初始化语法:[&#39;tom&#39;,‘jerry’]元组(tuple):只读,值可以重复,...

python实例 2-12306抢票(二) 下单

第二篇 刷票与下单1.记住登陆上一篇写了登陆:http://www.tnblog.net/cz/article/details/162 为了方便调试 不让每次登陆都...

使用VS Code开发python

Vs Code开发Python可以很好的支持代码调试、智能提示、代码对齐等1:下载VS Codehttps://code.visualstudio.com/Downloadvs ...

python变量与命名

Python使用等号 ( = ) 作为赋值运算符,例如a = 66 就是一条赋值语句,作用就是将66赋值给变量a。Python是弱类型语言,弱类...

python关键字和内置函数

Python中包含了如下所示的关键字:上面这些关键字都不能作为变量名。另外,Python 3还提供了如下表所示的内置函数:也不能...

python基础输入和输出

Python使用print()函数向打印程序输出,采用input()函数接收程序输入。print()函数的语法格式如下:print(value,...,sep=&#...

python基本数据类型

Python包含两大类基本数据类型:数值类型、字符串类型,三大类组合数据类型:集合类型、序列类型和字典类型.数值类型:整型...

python中通过fake_useragent生成随机UserAgent

fake_useragent第三方库,来实现随机请求头的设置;GitHub ---&gt; https://github.com/hellysmile/fake-useragent安...

python 升级pip

一条命令即可: python -m pip install --upgrade pip 安装成功后,一般是在python目录下面的Scripts里边的

python html编码解码

使用方法:html.escape(s)与html.unescape即可 import html s=&quot;&lt;div&gt;jsdlfjsl&lt;/div&gt;&quot; #html编...