热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

pythonpygame贪吃蛇代码_pygame写贪吃蛇

python小白尝试写游戏..学了点pygame不知道那什么练手好,先拿贪吃蛇开刀吧.一个游戏可以粗略的分为两个部分:数据(变量)处理数据(函数,方法)设计变量首先预想下,画面的那

python小白尝试写游戏..

学了点pygame不知道那什么练手好,先拿贪吃蛇开刀吧.

一个游戏可以粗略的分为两个部分:

数据(变量)

处理数据(函数,方法)

设计变量

首先预想下,画面的那些部分需要存储在变量里

整个画面上只会有矩形,而且这些矩形整整齐齐,大小相等,原本一个矩形需要四个变量表示位置,这里,只需要两个变量(行数,列数)就能表示方块的位置

蛇头,食物可以用二元元组表示,蛇身的数量不确定,只能用包含数个元组的列表表示

另外设定窗口大小800x600,每个方块都是50x50

importpygameimportsys

pygame.init()

screen= pygame.display.set_mode((800, 600))

pygame.display.set_caption("贪吃蛇")

food= (4, 5)

body= [(1, 1),(1,2)]

head= (1, 3)

BLOCK=0, 0, 0

GREEN= 0, 255, 0

RED= 255, 0, 0

BLUE= 0, 0, 255WHITE= 255, 255, 255

while 1:for event inpygame.event.get():if event.type ==pygame.QUIT:

sys.exit()

变量设定好了,游戏已经完成了一半( ̄▽ ̄)~*

下一步

变量到画面

pygame.draw.rect()是根据矩形四元数组绘制图像的,那就写个函数"对接"下我的二元坐标

这里就成数学的问题了...

defnew_draw_rect(zb, color,screen):

pygame.draw.rect(screen,color,((zb[1]-1)*50+1,(zb[0]-1)*50+1,48,48))

鉴于50x50时相邻方块们会"粘"在一起,方块向里收一下成48x48        ↑

绘制图形,

...

while 1:for event inpygame.event.get():if event.type ==pygame.QUIT:

sys.exit()

screen.fill(WHITE)

new_draw_rect(food, RED, screen)for i inbody:

new_draw_rect(i, BLUE, screen)

new_draw_rect(head, GREEN, screen)

pygame.display.update()

由静到动

两个问题:

1.什么时候动

2.怎么动

问题1,什么时候动,这里有两个思路,

间隔固定时间(1秒),动一次

按一次键动一次,无操作一定时间(1秒)后,重复最后一次操作

看起来第一种方案 简单 不错

首先,先用pygame的clock类限制帧率(100帧),以方便计时

再者,加入新变量times,times每次加1,超过一百就"动一动"

加入新变量direction,表示蛇头朝向,衔接键盘操作和"怎么动"

PS:程序结束之前,很难知道要用多少变量

importpygameimportsys

pygame.init()

screen= pygame.display.set_mode((800, 600))

pygame.display.set_caption("贪吃蛇")

fclock=pygame.time.Clock()

food= (4, 5)

body= [(1, 1)]

head= (1, 2)

times=0

direction= 'right'BLOCK=0, 0, 0

GREEN= 0, 255, 0

RED= 255, 0, 0

BLUE= 0, 0, 255WHITE= 255, 255, 255

defnew_draw_rect(zb, color,screen):

pygame.draw.rect(screen,color,((zb[1]-1)*50+1,(zb[0]-1)*50+1,48,48))pass

while 1:for event inpygame.event.get():if event.type ==pygame.QUIT:

sys.exit()elif event.type ==pygame.KEYDOWN:if event.key ==pygame.K_UP:

direction= "up"

elif event.key ==pygame.K_LEFT:

direction= "left"

elif event.key ==pygame.K_DOWN:

direction= "down"

elif event.key ==pygame.K_RIGHT:

direction= "right"

if times >= 100:pass#动一动

times =0else:

times+= 1screen.fill(WHITE)

new_draw_rect(food, RED, screen)for i inbody:

new_draw_rect(i, BLUE, screen)

new_draw_rect(head, GREEN, screen)

fclock.tick(100)

pygame.display.update()

蛇头的运动规律 : 向临近的格子移动,上下左右具体那个格子由键盘确定

那就写个新函数去生成蛇头的新位置

defget_front(head,direction):

x, y=headif direction == "up":return x-1, yelif direction == "left":return x, y-1

elif direction == "down":return x+1, yelif direction == "right":return x, y+1

然后

head = get_front(head,direction)

但是蛇蛇一头扎墙里怎么办.......

你的好友【front : 临时记下蛇头前方的位置】已上线

你的好友【alive : 记录存活信息】已上线

PS:front可以不是全局变量

defask_alive(front,body):

x, y&#61;frontif x <0 or x > 12 or y <0 or y >16:returnFalseif front inbody:returnFalsereturn True

然后这样用

front &#61; get_front(head,direction)

alive &#61; ask_alive(front,body)

if alive:

head &#61; front

人话 :先看看蛇头前面是否有危险,有危险就死了 , 不动啦

另外alive得加到前面的if里面当限制条件,死了就不能乱动啦~~~~~

蛇身动的规律 : 近头端跟头走,尾端也跟着走--向程序靠拢-->>用过的head加入body,同时删去body最老的成员

这里可以看出body必须有序,可变.python里面就用列表了

如果使用list的append方法,head加在body的末尾,那么body[0]就会是"最老的成员"就得使用pop(0)删去

PS. body.append(head)得写在head&#61;front前面,在head更新前加进body

if times >&#61; 100 andalive:

front&#61;get_front(head,direction)

alive&#61;ask_alive(front,body)ifalive:

body.append(head)

head&#61;front

body.pop(0)

times&#61;0else:

times&#43;&#61; 1

食物的运动规律:被吃掉后,随机位置再出现 --向程序靠拢-->> 当head&#61;&#61; food为真时 food随机选择一个蛇之外的地方出现

defnew_food(head,body):while 1:

x&#61; random.randint(1, 12)

y&#61; random.randint(1, 16)if (x, y) !&#61; head and (x, y) not inbody:return x, y

这里存在一个隐式BUG,要是蛇充满了每一个角落,那这就是死循环 ...........然后整个程序卡在这里....

版本1 : 我选择没看见,不会有什么人能吃到"全屏"的(´⊙ω⊙&#96;)    --来自开发者的懒惰

版本2 【我的选择】: 修了这个BUG

defnew_food(head,body):

i&#61;0while i <100:

x&#61; random.randint(1, 12)

y&#61; random.randint(1, 16)if (x, y) !&#61; head and (x, y) not inbody:return(x, y), True

i&#43;&#61; 1

else:return(0, 0), False

food, alive&#61; new_food()

100次机会 否则就死(&#xffe3;へ&#xffe3;)     --来自开发者的恶意

另外,蛇吃了食物就要长一格&#61;&#61;&#61;&#61;>>蛇头前进一格,蛇尾不动,蛇就因此长了一格&#61;&#61;&#61;&#61;>>当head &#61; food 为真时body.pop(0)不用执行

ifalive:

body.append(head)

head&#61;frontif food &#61;&#61;head:

food&#61;new_food(head, body)else:

body.pop(0)

完结撒花

细节优化

1,

什么?游戏结束了?

黑个屏,提醒下

你的好友【back_color】已上线

back_color一开始等于WHITE , alive为假时变为BLOCK

标题栏变成"游戏结束"

if times >&#61; 100 andalive:front&#61;get_front(head, direction)

alive&#61;ask_alive(front, body)ifalive:

body.append(head)

head&#61;frontif food &#61;&#61;head:

food, alive&#61;new_food(head, body)else:

body.pop(0)else:

back_color&#61;BLOCK

pygame.display.set_caption("游戏结束")

times&#61;0else:

times&#43;&#61; 1

2,

要是一开始按了一下left......

恭喜你获得技能【撞脖子自杀】

要么那就

你的好友【old_direction】已上线

old_direction &#61; "right"

defdirection_yes_no(direction,old_direction):

d&#61; {"up": "down", "down": "up", "left": "right", "right": "left"}if d[direction] &#61;&#61;old_direction:returnold_directionreturn direction

PS : 字典代替if-elif结构省心省时

然后

if times >&#61; 100 andalive:

direction&#61;direction_yes_no(direction, old_direction)

old_direction&#61;direction

front&#61;get_front(head, direction)

alive&#61; ask_alive(front, body)

人话 : 添加一个变量记录上一次有效的输入,两个方向关系不正确时,以老变量为准--向人靠拢-->>向右跑时,不准向左!!!

Q : direction也可以在按键事件处理时限制呀,例如

elif event.type &#61;&#61;pygame.KEYDOWN:if event.key &#61;&#61;pygame.K_UP:

direction&#61; "up"

"""改为"""

elif event.type &#61;&#61;pygame.KEYDOWN:if event.key &#61;&#61;pygame.K_UP:if direction !&#61; "down"direction&#61; "up"

A:在发现这个方法的BUG之前,我也是这样想的

还是上面的例子

直接按left行不通,right--XX-->left

先按down,迅速再按left ,,right --pass-->> down --pass-->> left

恭喜你获得技能【绕过开发者防护,高水平撞脖子自杀】

3,

Q : 我要暂停!!!

A : 好好玩游戏,不要动不动就暂停

你的好友【pause】已上线

逻辑值,P键控制

pause &#61;Falseelif event.key &#61;&#61;pygame.K_p:

pause&#61; notpauseif times >&#61; 100 and alive and (notpause):

....

下面我发一下全部的代码,代码包含上面的优化

↓↓↓↓

完结撒花

importpygameimportsysimportrandom

pygame.init()

screen&#61; pygame.display.set_mode((800, 600))

pygame.display.set_caption("贪吃蛇")

fclock&#61;pygame.time.Clock()

food&#61; (4, 5)

body&#61; [(1, 1)]

head&#61; (1, 2)

times&#61;0

direction&#61; "right"old_direction&#61; "right"alive&#61;True

pause&#61;False

BLOCK&#61;0, 0, 0

GREEN&#61; 0, 255, 0

RED&#61; 255, 0, 0

BLUE&#61; 0, 0, 255WHITE&#61; 255, 255, 255back_color&#61;WHITEdefnew_draw_rect(zb, color,screen):

pygame.draw.rect(screen,color,((zb[1]-1)*50&#43;1,(zb[0]-1)*50&#43;1,48,48))defget_front(head, direction):

x, y&#61;headif direction &#61;&#61; "up":return x-1, yelif direction &#61;&#61; "left":return x, y-1

elif direction &#61;&#61; "down":return x&#43;1, yelif direction &#61;&#61; "right":return x, y&#43;1

defask_alive(front, body):

x, y&#61;frontif x <0 or x > 12 or y <0 or y >16:returnFalseif front inbody:returnFalsereturnTruedefnew_food(head, body):

i&#61;0while i <100:

x&#61; random.randint(1, 12)

y&#61; random.randint(1, 16)if (x, y) !&#61; head and (x, y) not inbody:return(x, y), True

i&#43;&#61; 1

else:return(0, 0), Falsedefdirection_yes_no(direction, old_direction):

d&#61; {"up": "down", "down": "up", "left": "right", "right": "left"}if d[direction] &#61;&#61;old_direction:returnold_directionreturndirection

#food &#61; new_food(head,body)while 1:for event inpygame.event.get():if event.type &#61;&#61;pygame.QUIT:

sys.exit()elif event.type &#61;&#61;pygame.KEYDOWN:if event.key &#61;&#61;pygame.K_UP:

direction&#61; "up"

elif event.key &#61;&#61;pygame.K_LEFT:

direction&#61; "left"

elif event.key &#61;&#61;pygame.K_DOWN:

direction&#61; "down"

elif event.key &#61;&#61;pygame.K_RIGHT:

direction&#61; "right"

elif event.key &#61;&#61;pygame.K_p:

pause&#61; notpauseif times >&#61; 100 and alive and (notpause):

direction&#61;direction_yes_no(direction, old_direction)

old_direction&#61;direction

front&#61;get_front(head, direction)

alive&#61;ask_alive(front, body)ifalive:

body.append(head)

head&#61;frontif food &#61;&#61;head:

food, alive&#61;new_food(head, body)else:

body.pop(0)else:

back_color&#61;BLOCK

pygame.display.set_caption("游戏结束")

times&#61;0else:

times&#43;&#61; 1screen.fill(back_color)

new_draw_rect(food, RED, screen)for i inbody:

new_draw_rect(i, BLUE, screen)

new_draw_rect(head, GREEN, screen)

fclock.tick(100)

pygame.display.update()

↑↑↑↑

↑↑↑↑

↑↑↑↑

4,

Q : 游戏结束或者暂停后因为times >&#61; 100 and alive and (not pause)始终为假

times &#43;&#61; 1 一直运行,,,,会不会不太妥当

A : 又不会溢出,,,,,,,,取消暂停时蛇能迅速跑起来要是time&#61;&#61;100那问题就大了,,幸亏当初留了些余地写成 >&#61;

(&#xff5e;&#xffe3;▽&#xffe3;)&#xff5e;

5,

Q : 蛇跑的太慢我想加速

A : 上面的times>&#61;100的100随便改一下就行

0->100动一动   变成    0->80 动一动

或者动前面的数

0->100动一动   变成    20->100动一动

或者将它设置成变量让它随蛇的长度变化而变化

6,

打字太累,,

direction那里可以使用0,1,2,3

代替 up left down right

键盘事件和get_front()得用同一套词

7,

Q : 第一个food的位置是固定的,不能"动"吗?

A : 因为我是先定义变量,再定义函数

food &#61; new_food(head,body)

就得写在定义函数后面,我不忍心让它一个变量孤单,,,,怕你看不到(写了但注释掉了)

动手术

前面说过

问题1,什么时候动,这里有两个思路,

间隔固定时间(1秒),动一次

按一次键动一次,无操作一定时间(1秒)后,重复最后一次操作

看起来第一种方案 简单 不错

当初我以为第二种方案很难,,,

写了这个博客后实力大增ᕦ( ᴼ ڡ ᴼ )ᕤ

现在我不怕了

第一个方法,

处理按键事件后times &#61; 100 ,例

if event.key &#61;&#61;pygame.K_UP:

direction&#61; "up"times&#61; 100

elif event.key &#61;&#61;pygame.K_LEFT:

direction&#61; "left"times&#61; 100

while循环当轮就能动一动

隐藏操作 : 在0.01s内按下两个键,第一个按的不会"生效"

pygame : 我得跑完事件列表的每个元素

这是假的第二方案!!!

第二个方法,

把"动一动"的全部代码,打包成函数或者直接写在按键处理的后面

就是上面times &#61; 100的位置 例

if event.key &#61;&#61;pygame.K_UP:

direction&#61; "up"

&#39;动一动&#39;

elif event.key &#61;&#61;pygame.K_LEFT:

direction&#61; "left"

&#39;动一动&#39;

记住关键的一点times &#61; 0也算"动一动"的内容,第二方案里,按键后计时需要清零!!!

if times >&#61; 100 and alive and (notpause):

direction&#61;direction_yes_no(direction, old_direction)

old_direction&#61;direction

front&#61;get_front(head, direction)

alive&#61;ask_alive(front, body)ifalive:

body.append(head)

head&#61;frontif food &#61;&#61;head:

food, alive&#61;new_food(head, body)else:

body.pop(0)else:

back_color&#61;BLOCK

pygame.display.set_caption("游戏结束")

times&#61;0else:

times&#43;&#61; 1

为了防止"诈尸"

"动一动"前还得加上if alive and (not pause):

times没必要加

我就懒得管了(╥╯^╰╥)这篇文章写了太长时间,现在已经看不懂当初的代码了

Q : 不知道你是不是记得我,优化2就是我问的.....是这样的,我对我的方法还不死心...."动手术"改第二方案后能用吗?

elif event.type &#61;&#61;pygame.KEYDOWN:if event.key &#61;&#61;pygame.K_UP:

direction&#61; "up"

"""改为"""

elif event.type &#61;&#61;pygame.KEYDOWN:if event.key &#61;&#61;pygame.K_UP:if direction !&#61; "down"direction&#61; "up"

A : 对于第一方法实现的第二方案还是会有小毛病

while循环当轮就能动一动

隐藏操作 : 在0.01s内按下两个键,第一个按的不会"生效"

pygame : 我得跑完事件列表的每个元素

在0.01s内,按下两个键,就可以照旧触发【秘技: 撞脖子自杀】

第二方法实现的应该没问题.......

完结撒花✿✿ヽ(°▽°)ノ✿

Q : 我想在加宽屏幕在右侧显示一下时间分数之类的信息,你还有什么"交待"吗?

A : 在pygame显示字体比较有难度....我只能祝你程序不出BUG...另外点(800,0)到点(800,600)别忘了画到线,提醒玩家"边界"还是存在的,让玩家摔键盘动怒就不好了

Q : 我就是对你的颜色搭配有意见,颜色有点扎眼....

A : 我又不是美工,,,,,,,,,,,,颜色搭配的问题,应该,,,,,,,,,应该可以原谅,,,,,,,,,,

Q : 游戏太没挑战性,加点障碍物呗~~

A : walls 会在ask_alive()和new_food()用到,加个if的问题,,,,另外绘制屏幕那里多加个for,,,,,

我就懒得管了(╥╯^╰╥)这篇文章写了太长时间,现在已经看不懂当初的代码了

完结撒花✿✿ヽ(°▽°)ノ✿

这次真没了..✿✿ヽ(°▽°)ノ✿

如有疏漏,欢迎补充



推荐阅读
  • Python教学练习二Python1-12练习二一、判断季节用户输入月份,判断这个月是哪个季节?3,4,5月----春 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 开源Keras Faster RCNN模型介绍及代码结构解析
    本文介绍了开源Keras Faster RCNN模型的环境需求和代码结构,包括FasterRCNN源码解析、RPN与classifier定义、data_generators.py文件的功能以及损失计算。同时提供了该模型的开源地址和安装所需的库。 ... [详细]
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • importjava.util.ArrayList;publicclassPageIndex{privateintpageSize;每页要显示的行privateintpageNum ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • Python使用Pillow包生成验证码图片的方法
    本文介绍了使用Python中的Pillow包生成验证码图片的方法。通过随机生成数字和符号,并添加干扰象素,生成一幅验证码图片。需要配置好Python环境,并安装Pillow库。代码实现包括导入Pillow包和随机模块,定义随机生成字母、数字和字体颜色的函数。 ... [详细]
  • OpenMap教程4 – 图层概述
    本文介绍了OpenMap教程4中关于地图图层的内容,包括将ShapeLayer添加到MapBean中的方法,OpenMap支持的图层类型以及使用BufferedLayer创建图像的MapBean。此外,还介绍了Layer背景标志的作用和OMGraphicHandlerLayer的基础层类。 ... [详细]
author-avatar
将登太行的2602939913
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有