002_Snake_FreePythonGames用海龟画图实现简单的贪吃蛇游戏
一 相关知识
1 randrange()函数
- 功能:randrange() 方法返回指定递增基数集合中的一个随机数,基数默认值为1。
- 语法:random.randrange ([start,] stop [,step])
- 注意:randrange()是不能直接访问的,需要导入 random 模块,然后通过 random 静态对象调用该方法。
- 方法一:import random
- 方法二:from random import randrange
- 注意:randrange()是不能直接访问的,需要导入 random 模块,然后通过 random 静态对象调用该方法。
- 参数:
- start -- 指定范围内的开始值,包含在范围内。
- stop -- 指定范围内的结束值,不包含在范围内。
- step -- 指定递增基数。
- 返回值:从给定的范围返回随机项。
2 turtle.tracer()函数
- 功能:启用/禁用海龟动画并设置刷新图形的延迟时间。——可看作是为了加快/减慢作图的,你可以在里面添加参数
- 语法:turtle.tracer(n=None,delay=None)
- 如果指定 n 值,则只有每第 n 次屏幕刷新会实际执行。(可被用来加速复杂图形的绘制。) 如果调用时不带参数,则返回当前保存的 n 值。第二个参数设置延迟值
- n -- 非负整型数;delay -- 非负整型数
- turtle.tracer(False)或者duturtle.tracer(0):图形将一次性画好
- turtle.tracer(1):图形按照正常速度进行,可有可无
- turtle.tracer(4):在循环中,图形将一次画出4次循环的图
3 turtle.update():执行一次 TurtleScreen 刷新。在禁用追踪时使用。
4 turtle.clear():从中删除所有海龟的全部绘图。将已清空的 TurtleScreen 重置为初始状态: 白色背景,无背景片,无事件绑定并启用追踪。
5 turtle.ontimer(fun,t):安装一个计时器,在tms后调用fun函数
二 分析过程https://www.jb51.net/article/153788.htm
贪吃蛇的身体是由list构成的,list中每一个元组代表贪吃蛇在棋盘上的坐标,我们只需在这些位置画上图案,就能制作出一条圆滚滚的贪吃蛇来。但是如果想让贪吃蛇活蹦乱跳,我们就要写一个move函数。
1贪吃蛇怎么移动
如果贪吃蛇没吃到食物,那么我们就删除list中最后一个坐标,再在蛇头部分插入新的位置。如何确定新的位置呢,我们就要设定贪吃蛇移动的方向(x,y),将原蛇头位置的坐标在移动方向上进行加减操作。这样贪吃蛇就实现了向前移动的目标。如果贪吃蛇恰好吃到了食物,唯一的不同就是不需要删除贪吃蛇尾部的元素。其中需要注意的是,贪吃蛇不能朝着当前移动方向的反方向移动。体现在代码中,就是当前方向与改变方向的乘积不能为负值。
2 如何知道贪吃蛇吃到了食物呢
如果贪吃蛇蛇头的坐标与食物的坐标重合的话,贪吃蛇就吃到了食物。如果贪吃蛇吃到了食物,就在棋盘上随机更新食物。如果随机生成的食物的坐标,恰好与贪吃蛇的位置重合的话,就继续随机产生坐标,直到确保与贪吃蛇的坐标不同的时候。
3 如何知道游戏失败了呢
如果贪吃蛇蛇头的坐标与边框的坐标重合的话,蛇卒。如果贪吃蛇各个部分的坐标有重合的话,就说明贪吃蛇咬到了自己,游戏结束。
三 代码
代码功能都是齐全的,然后按键控制onkey函数中的参数是'Right',我一直以为是通过输入这个字符串控制贪吃蛇移动的,结果它的意思是按键盘上的向上的方向键,并不是输入字符串,所以我一直没办法通过键盘控制贪吃蛇的移动方向,导致我还以为是代码有问题。。。。
然后跟原来的代码相比,我加了一部分改变食物位置的changeFood函数,原理跟改变贪吃蛇移动方向的changeSnake函数一致。
该贪吃蛇程序是利用turtle库完成的,网上很多贪吃蛇代码都是利用pygame库实现的,那些资料里面可能游戏开始结束设置的比较全面一点,但是用turtle库感觉简单了好多有木有!!!
1 """Snake,classic arcade game 2 Exercise 3 1. How do you make the snake faster or slower? 通过改变ontimer(move,500)语句中的第二个参数 4 2. How can you make the snake go around the edges?可将初始坐标定为(180,0)、(-180,0)、(0,180)、(0,-180)、(180,180)、(-180,180)、(180,-180)、(-180,-180) 5 3 How would you move the food? 通过onkey函数调用changeFood函数改变食物坐标 6 4. Change the snake to respond to arrow keys. 已经实现了吧,Right、Left、Up、Down分别对应向右、向左、向上、向下箭头 7 """ 8 9 from turtle import * # 导入turtle库,此种方式导入可直接使用库内函数,不使用trutle.做前导 10 from random import randrange # 从random库中导入randrange()函数,使food随机出现 11 from freegames import square,vector # 从freegames库中导入square和vector,用square正方形表示food、snake,用vector这个二维向量表示snake 12 13 food = vector(0,0) # 初始化food变量,用来表示第一个食物在坐标为(0,0)处 14 snake = [vector(180,0)] # 初始化snake,而且snake是列表,其元素是向量 15 aim = vector(0,-10) # 用来控制贪吃蛇的移动方向和距离 16 aim2 = vector(10,10) # 用来控制食物移动的方向和距离 17 18 19 def changeSnake(x,y): # 改变贪吃蛇移动方向部分,通过onkey函数和lambda表达式调用changeSnake函数,获得下一个移动坐标(x,y) 20 "Change snake direction." 21 aim.x = x # 将x的值赋给aim.x改变贪吃蛇目标的横坐标 22 aim.y = y # 将y的值赋给aim.x改变贪吃蛇目标的纵坐标 23 24 def changeFood(x,y): # 改变食物移动方向部分,通过onkey函数和lambda表达式调用changeFood函数,获得下一个移动坐标(x/2,y/2) 25 "Change food direction." 26 aim2.x = x/2 # 将x/2的值赋给aim2.x改变食物目标的横坐标 27 aim2.y = y/2 # 将y/2的值赋给aim2.y改变食物目标的纵坐标 28 29 def inside(head): # 判断贪吃蛇有没有碰到画布边界部分,限制贪吃蛇的移动范围 30 "Return True if head inside the boundaries." 31 return -200 < head.x < 190 and -200 < head.y < 190 32 33 def move(): 34 "Move snake forward one segment." 35 # 更改食物和贪吃蛇蛇头坐标 36 head = snake[-1].copy() # 表示复制snake列表的最后一个元素,这里用列表的最后一个元素表示蛇头 37 head.move(aim) # 每调用一次move函数,贪吃蛇就移动到(head.x+aim.x,head.y+aim.y)的位置 38 food.move(aim2) # 每调用一次move函数,食物就移动到(food.x+aim2.x,food.y+aim2.y)的位置 39 40 #判断游戏是否结束 41 if not inside(head) or head in snake: # 判断是否结束游戏部分:head碰到墙壁|头碰到身体 42 square(head.x,head.y,9,'red') # 将贪吃蛇蛇头的正方形改成红色,表示游戏结束 43 update() # 执行一次屏幕刷新 44 return # 用来终止程序的运行,其后语句不会再执行 45 46 # 更新贪吃蛇的身体 47 snake.append(head) # 蛇头坐标已经更改,将新的蛇头目标添加到snake列表中 48 49 if head == food: # snake吃到food,下一个food会随机出现在画布的另一个地方 50 print('Snake',len(snake)) # 打印贪吃蛇的长度 51 food.x = randrange(-15,15) * 10 # 随机产生食物横坐标 52 food.y = randrange(-15,15) * 10 # 随机产生食物纵坐标 53 else: # snake没有吃到food 54 snake.pop(0) # snake没有吃到食物,所以将snake列表最后一个元素删除,保持贪吃蛇长度不变,这里用列表的第一个元素表示蛇尾 55 56 # 清空画布,重新画好食物和贪吃蛇的位置,利用ontimer函数调用move函数,控制贪吃蛇进行下一次移动 57 clear() # 相当于刷新操作,将所有的绘图全部删了 58 59 for body in snake: # 重新画出贪吃蛇的身体部分 60 square(body.x,body.y,9,'black') # 黑色方块表示贪吃蛇的身体 61 square(food.x,food.y,9,'green') # 画出食物,绿色方块表示食物 62 update() # 执行一次屏幕刷新 63 ontimer(move,500) # 经过500ms后继续调用move函数 64 65 setup(420,420,370,0) # 初始画布尺寸 66 hideturtle() # 隐藏鼠标 67 tracer(False) # 保证画图操作(食物和贪吃蛇身体)一次性完成 68 move() 69 listen() # 监听,屏幕聚焦 70 # 绑定键盘方向,改变贪吃蛇的移动方向 71 onkey(lambda:changeSnake(10,0),'Right') # 右转,Right是键盘方向键的右键,不是输入单词Right 72 onkey(lambda:changeSnake(-10,0),'Left') # 左转 73 onkey(lambda:changeSnake(0,10),'Up') # 向上走 74 onkey(lambda:changeSnake(0,-10),'Down') # 向下走 75 # 绑定键盘方向,改变食物的移动方向 76 onkey(lambda:changeFood(10,0),'D') # 右转,在键盘上输入大写字母'D' 77 onkey(lambda:changeFood(-10,0),'A') # 左转 78 onkey(lambda:changeFood(0,10),'W') # 向上走 79 onkey(lambda:changeFood(0,-10),'S') # 向下走 80 81 done()