目录
综述
turtle库是Python的一个图形绘制库,它可以通过简单的命令来控制一个小海龟在窗口上绘制图形。这个库的设计灵感来自于Logo语言,它可以帮助初学者学习编程和算法思维。
使用turtle库,可以通过一系列的命令,如前进、后退、转向等,来控制小海龟在屏幕上绘制线条。可以通过调整参数,如颜色、粗细、速度等,来改变绘制的效果。
turtle库提供了一些基本的绘制函数,如绘制线条、填充区域、绘制图形等。同时,它也提供了一些控制函数,如控制海龟的形状、颜色、速度等。
除了基本的绘制功能,turtle库还提供了一些高级的函数,如循环绘制、条件绘制、事件绑定等,可以帮助用户实现更复杂的图形绘制。
总之,turtle库是一个简单易用的图形绘制库,适合初学者学习编程和算法思维。通过使用turtle库,可以让编程变得更加有趣和直观。
我们今天就要用画图函数来实现贪吃蛇这个项目。
制作前的分析
任务分析
贪吃蛇是一款经典的游戏,玩家通过操控蛇的移动来获取食物并防止蛇头和身体相撞。以下是对贪吃蛇游戏的分析:
-
游戏规则:贪吃蛇游戏由一条初始长度为1的蛇和一些随机分布的食物组成。玩家通过控制蛇的移动方向,使蛇头接触食物从而增长身体长度。蛇头碰到边界或者蛇身时游戏结束。分数通常是根据蛇吃到的食物数量计算的。
-
游戏机制:贪吃蛇游戏基于一个二维的游戏界面,蛇和食物都是由方块或者圆形图形表示。蛇的移动速度可以是固定的,也可以是随时间逐渐增加的。蛇每次移动时,蛇头向前移动一个单位,并将每个身体部分移动到前一个身体部分的位置。这里我们会用到数组来存储蛇头和蛇身,我们需要着重了解蛇的运动到底是如何实现的。
-
碰撞检测:游戏中的碰撞检测是非常重要的。需要检测蛇头是否碰撞到了食物,如果是,则将食物添加到蛇的身体上,并且生成新的食物。还需要检测蛇头是否碰到了边界或者蛇身,如果是,则游戏结束。这里其实就是判定一下坐标是否重合就可以实现。
-
难度递增:一般来说,贪吃蛇游戏的难度是逐渐递增的。随着蛇的身体长度增加,蛇移动的速度也会增加。这会增加游戏的挑战性,使玩家需要更快地做出决策。这更多是出于对游戏性的考虑,跟游戏设计有关,是你作为程序可以思考的一部分内容。
对象分析
构成贪吃蛇的元素包括蛇身、食物和游戏地图。
-
蛇头,蛇身:蛇身由多个相邻的方块组成,每个方块代表一个身体部分。蛇身具有一个头部和一个尾部,头部代表蛇的移动方向,尾部代表蛇的长度。
-
食物:食物是蛇需要吃的目标,出现在地图的随机位置。当蛇吃到食物时,蛇的长度增加,分数也会得到增加,吃掉食物,食物应该刷新。我们也可以设计多种食物来增加游戏性。
-
游戏地图:游戏地图是一个二维的方格区域,蛇在地图上移动。地图上的空白方格代表蛇可以移动的位置,蛇不能穿过自己的身体或撞到边界。
我们可以看出,其实绘制蛇,地图,食物都可以用同一元素实现,比如方块或者圆圈,想毕现在学过turtle函数的朋友们就有了一些思路。
编程思路分析
我们需要用到的有以下四种
-
碰撞检测:在每一帧更新蛇的位置时,需要检测蛇头是否碰到了食物或身体的其他部分,以及是否撞到了边界。如果蛇头与食物碰撞,蛇的长度增加,并在地图上生成新的食物。如果蛇头碰撞到身体或边界,游戏结束。
-
蛇的移动:蛇的移动是通过改变蛇头的位置来实现的。每一帧更新蛇的位置时,根据蛇当前的移动方向,将蛇头的位置向前移动一个方格,并将原来的蛇头变为身体的一部分。同时,将蛇尾的位置向前移动一个方格,并将其从蛇身中移除。
-
控制输入:玩家可以通过键盘输入来改变蛇的移动方向。通过监听键盘事件,根据玩家的输入来改变蛇的移动方向,而且也要避免玩家在向下移动的时候误触了上键导致蛇回头自杀。
-
随机生成:食物在地图上的位置是随机生成的,以增加游戏的可变性。在生成食物时,需要避免生成在蛇的身体上。
那我们做好了基本的分析,就可以开始代码的讲解了。
代码块
引用
turtle库:主要用于画图和画布的布置。
sleep库:控制时延的。
random库:随机数的生成。
from turtle import *
from random import randrange
from time import sleep
定义变量
详情见代码注释
################定义变量和方法################
###方块绘画方法的构建
def square(x,y,size,color_name):
up()#抬笔
goto(x,y)#到达x,y的位置
down()#落笔
color(color_name)#选择一个你喜欢的颜色
begin_fill()
forward(size)
left(90)
forward(size)
left(90)
forward(size)
left(90)
forward(size)
left(90)
end_fill()
"""填充"""
snake=[[0,0],[10,0],[20,0],[30,0],[40,0],[50,0]]#蛇的构建
"""水果的随机生成"""
apple_x=randrange(-20,18)*10
apple_y=randrange(-19,19)*10
'''初始移动距离的规定'''
aim_x=10
aim_y=0
t=120 #时间
score=0#分数
p=0#标记位
函数
函数一:change(x,y)
输入:键盘的w,a,s,d
作用:改变蛇的移动方向
注意:要有方向相反不改变的思考
################定义函数################
def change(x,y):
global aim_x,aim_y
if aim_x+x!=0 or aim_y+y!=0:
aim_x=x
aim_y=y
'''当改变的方向与之前的方向相反,则不改变方向'''
函数二:inside_map()
输入:无
作用:判断是否撞墙
注意:无
tips:其实就是判断蛇的数组存储的位置是否和地图边缘重合
def inside_map():
if -200<=snake[-1][0]<=180 and -190<=snake[-1][1]<=190:
return True
else:
return False
'''判断是否撞墙'''
函数三:inside_snake()
输入:无
作用:判断是否撞到自己
注意:无
tips:其实就是遍历身子是否和头的坐标重合
def inside_snake():
for n in range(len(snake)-1):
if snake[-1][0]==snake[n][0] and snake[-1][1]==snake[n][1]:
return True
return False
'''判断是否吃到自己'''
函数四:def fruit_appear ()
输入:无
作用:生成一个果子
注意:不应该和蛇的身子重合
def fruit_appear ():
global apple_x,apple_y
apple_x=randrange(-20,18)*10
apple_y=randrange(-19,19)*10
for n in range(len(snake)-1) :
if snake[n][0]==apple_x and snake[n][1]==apple_y:
apple_x=randrange(-20,18)*10
apple_y=randrange(-19,19)*10
fruit_appear()
'''水果的生成机制,以及预防生成在与蛇重叠的位置'''
函数五:gameLoop()
输入:无
作用:游戏的正常运行
注意:无
def gameLoop():
global apple_x,apple_y,snake,aim_x,aim_y,t,score,p
'''蛇本身的机制:包括吃到苹果和蓝莓以及没有吃到任何东西的情况下如何移动和增长'''
if p!=1:...
else:...
if snake[-1][0]!=apple_x or snake[-1][1]!=apple_y:...
else:
'''死亡判定'''
if not inside_map() or inside_snake():
'''要及时清除之前的画,否则会形成很长的拖影'''
clear()
'''与turtle画相关的程序'''
square(-210,-200,410,"black")
square(-200,-190,390,"white")
for n in range(len(snake)):
square(snake[-1][0],snake[-1][1],10,"black")
if score%5!= 4:
else:
'''每t毫秒我们运动一下'''
ontimer(gameLoop,t)
update()
接下来我们进行更细节的拆解
蛇吃东西的机制
有一个蓝莓的生成判定,以及加速的游戏性提升,需要花时间看一下。注释笔者尽量写得详细,有问题可以多讨论。
'''蛇本身的机制:包括吃到苹果和蓝莓以及没有吃到任何东西的情况下如何移动和增长'''
if p!=1:
snake.append([snake[-1][0]+aim_x,snake[-1][1]+aim_y])
else:
for i in range(5):
snake.append([snake[-1][0]+aim_x,snake[-1][1]+aim_y])
p=0#判断标志符,用于生成蓝莓
if snake[-1][0]!=apple_x or snake[-1][1]!=apple_y:
snake.pop(0)#如果没有吃到食物,就要删除末尾,这样才不会长长,反之吃到食物则不用删除
else:
score=score+1
print(score)#用于调试
if score%5==0 and t>=30:
t=t-10
p=p+1
"""用于加速,提高难度,但是要有峰值"""
fruit_appear()
死亡判定
需要做一些死亡提示和延时表现,另外也要做初始化,让游戏保持循环。
'''死亡判定'''
if not inside_map() or inside_snake():
square(snake[-1][0],snake[-1][1],10,"red")#蛇头红提示
update()
sleep(2)#程序延时,可调整
'''初始化'''
snake=[[0,0],[10,0],[20,0],[30,0],[40,0],[50,0]]
fruit_appear()
aim_x=10
aim_y=0
t=150
print("game over!the score is ",score)#便于调试
score=0
画图相关
一定要清除画面,因为如果不清除之前画面,会导致原有的画面依旧存在
然后就是画布,蛇以及果子的绘制。
具体看注释
'''要及时清除之前的画,否则会形成很长的拖影'''
clear()
'''与turtle画相关的程序'''
square(-210,-200,410,"black")
square(-200,-190,390,"white")
for n in range(len(snake)):
square(snake[n][0],snake[n][1],10,"gray")
square(snake[-1][0],snake[-1][1],10,"black")
if score%5!= 4:
square(apple_x,apple_y,10,"red")#苹果
else:
square(apple_x,apple_y,10,"blue")#蓝莓
'''每t毫秒我们运动一下'''
ontimer(gameLoop,t)
update()
主函数
########主程序##########
setup(420,420,0,0)#画布的设置
hideturtle()#隐藏0
tracer(False)
listen() #监听
'''看操作者是否做出操作'''
onkey(lambda: change(0,10),"w")
onkey(lambda: change(0,-10),"s")
onkey(lambda: change(-10,0),"a")
onkey(lambda: change(10,0),"d")
gameLoop()
done()
完整程序
你们最喜欢的环节,但是希望你在Ctrl+之前最好自己理解一下,因为这个想对来说简单很多,也是你作为程序的一个起步,还是希望你能好好学习完,然后水平更上一步。
from turtle import *
from random import randrange
from time import sleep
################定义变量和方法################
###方块绘画方法的构建
def square(x,y,size,color_name):
up()#抬笔
goto(x,y)#到达x,y的位置
down()#落笔
color(color_name)#选择一个你喜欢的颜色
begin_fill()
forward(size)
left(90)
forward(size)
left(90)
forward(size)
left(90)
forward(size)
left(90)
end_fill()
"""填充"""
snake=[[0,0],[10,0],[20,0],[30,0],[40,0],[50,0]]#蛇的构建
"""水果的随机生成"""
apple_x=randrange(-20,18)*10
apple_y=randrange(-19,19)*10
'''初始移动距离的规定'''
aim_x=10
aim_y=0
t=120 #时间
score=0#分数
p=0#标记位
################定义函数################
def change(x,y):
global aim_x,aim_y
if aim_x+x!=0 or aim_y+y!=0:
aim_x=x
aim_y=y
'''当改变的方向与之前的方向相反,则不改变方向'''
def inside_map():
if -200<=snake[-1][0]<=180 and -190<=snake[-1][1]<=190:
return True
else:
return False
'''判断是否撞墙'''
def inside_snake():
for n in range(len(snake)-1):
if snake[-1][0]==snake[n][0] and snake[-1][1]==snake[n][1]:
return True
return False
'''判断是否吃到自己'''
def fruit_appear ():
global apple_x,apple_y
apple_x=randrange(-20,18)*10
apple_y=randrange(-19,19)*10
for n in range(len(snake)-1) :
if snake[n][0]==apple_x and snake[n][1]==apple_y:
apple_x=randrange(-20,18)*10
apple_y=randrange(-19,19)*10
fruit_appear()
'''水果的生成机制,以及预防生成在与蛇重叠的位置'''
def gameLoop():
global apple_x,apple_y,snake,aim_x,aim_y,t,score,p
'''蛇本身的机制:包括吃到苹果和蓝莓以及没有吃到任何东西的情况下如何移动和增长'''
if p!=1:
snake.append([snake[-1][0]+aim_x,snake[-1][1]+aim_y])
else:
for i in range(5):
snake.append([snake[-1][0]+aim_x,snake[-1][1]+aim_y])
p=0
if snake[-1][0]!=apple_x or snake[-1][1]!=apple_y:
snake.pop(0)
else:
score=score+1
print(score)#用于调试
if score%5==0 and t>=30:
t=t-10
p=p+1
"""用于加速,提高难度,但是要有峰值"""
fruit_appear()
'''死亡判定'''
if not inside_map() or inside_snake():
square(snake[-1][0],snake[-1][1],10,"red")
update()
sleep(2)
snake=[[0,0],[10,0],[20,0],[30,0],[40,0],[50,0]]
fruit_appear()
aim_x=10
aim_y=0
t=150
print("game over!the score is ",score)
score=0
'''要及时清除之前的画,否则会形成很长的拖影'''
clear()
'''与turtle画相关的程序'''
square(-210,-200,410,"black")
square(-200,-190,390,"white")
for n in range(len(snake)):
square(snake[n][0],snake[n][1],10,"gray")
square(snake[-1][0],snake[-1][1],10,"black")
if score%5!= 4:
square(apple_x,apple_y,10,"red")#苹果
else:
square(apple_x,apple_y,10,"blue")#蓝莓
'''每t毫秒我们运动一下'''
ontimer(gameLoop,t)
update()
########主程序##########
setup(420,420,0,0)#画布的设置
hideturtle()#隐藏0
tracer(False)
listen() #监听
'''看操作者是否做出操作'''
onkey(lambda: change(0,10),"w")
onkey(lambda: change(0,-10),"s")
onkey(lambda: change(-10,0),"a")
onkey(lambda: change(10,0),"d")
gameLoop()
done()
总结
现在,你就用turtle函数写了一个属于你自己的贪吃蛇,一共一百多行,也不多,但是希望这能打开你对编程的兴趣,
如果有什么问题也欢迎在评论区和我讨论。
后续我可能更多会更新面向游戏的一些代码帖子(比如c#),主要还是想通过告诉别人来提升自己,能力有限,如果有什么不合理的地方欢迎指正。
如果你感兴趣,我还有一篇关于pygame的贪吃蛇,可以前往学习。