首先展示一下我们的效果图,由一个个大小为20*20的方块儿组成的贪吃蛇游戏
1.调用python开发环境,包括pygame、sys、random。
\# python 运行时的环境
import pygame, sys, random
2.调用pygame相关常量、还有配置颜色。
\# 这个模块包含所有pygame所使用的常量
from pygame.locals import \*
# 定义颜色变量
# 目标方块儿红颜色
redColor \= pygame.Color(255, 0, 0)
# 背景颜色为黑色
blackColor \= pygame.Color(0, 0, 0)
# 蛇颜色为白色
whiteColor \= pygame.Color(255, 255, 255)
3.定义游戏结束的函数 主要包含两部分操作,第一部分为pygame结束,第二部分为sys结束。
\# 定义游戏结束
def gameOver():
pygame.quit()
sys.exit()
4.有了前面的铺垫,我们可以正式开始设计我们的游戏,我将游戏内容存放到main函数中。
4.1初始化pygame,设定变量来控制蛇的速度,然后制作一个界面,界面的大小为640*480,界面标题为贪吃蛇。
其中界面大小是必须设定的,贪吃蛇游戏的规则之一便是不能触及边界,但界面的标题是可以不写的,界面标题默认为python文件名
特别注意pygame.display.set_mode()函数中需要插入为两项序列而不是整数型 所以参数应为(640, 480)
具体代码如下
def main():
# 初始化pygame
pygame.init()
# 定义一个变量 控制速度
fpsClock \= pygame.time.Clock()
# 创建一个窗口界面,界面大小为640\*480
playSurface \= pygame.display.set\_mode((640, 480))
# 界面标题为“贪吃蛇” 可不写,默认为python文件名
pygame.display.set\_caption('贪吃蛇')
4.2设定目标方块
目标方块是由计算机随机生成的,但在那之前需要我们手动设定一个初值,同时设定一个target_flag来判断目标方块是否被贪吃蛇 “吃” 掉
# 初始化目标方块的位置
targetPosition \= \[300, 300\]
# 目标方块标记 判断贪吃蛇是否吃掉目标方块 1为没吃掉 0为吃掉
targetFlag \= 1
4.3设定贪吃蛇的相关属性
初始化蛇需要注意什么?首先蛇的位置,其次蛇的长度,最后便是蛇的方向。那么一步步来实现
我们可以将蛇看做两部分组成组成,蛇头和蛇身。蛇身只要不断跟随蛇头便可,蛇头需要用来判断贪吃蛇的前进方向、是否结束游戏、是否 “吃” 掉目标方块儿等等
我们设定蛇头以(100, 100)为基准,蛇为水平方向放置,并且向右前进,所以蛇身的第一部分 应等于蛇头的’“Y”值,而“X”应当减去一个方块儿的位置,也就是减少20,贪吃蛇第一块应当是(80, 100)
设定存在方向的变量direction,初始方向向右,也需要设定改变方向的变量changedirection,令changedirection == direction
所写代码如下
# 初始化贪吃蛇的位置 (100,100)为基准
# 初始化贪吃蛇长度 列表中有几个元素 就有几个身体
snake\_head \= \[100, 100\]
snake\_body \= \[\[80, 100\], \[60, 100\]\]
# 初始化方向 默认为右
direction \= 'right'
# 定义一个认为控制的方向的变量
changedirection \= direction
4.4需要贪吃蛇动起来
特别说明 pygame的所有事件全都在一个实时循环中
由于操作比较简单,鼠标操作的便只有一个,点击右上角的叉叉关闭游戏,但键盘上的操作相对比较多 包括↑↓←→,控制蛇的移动,esc退出游戏
所以首先要判断发生的事件类型是点击QUIT ,又或者是KEYDOWN
QUIT不必说,游戏结束之前上面也有描述 pygame.quit() 与sys.exit()
KEYDOWN 就需要判断是上下左右的哪一个,发生按键要使得蛇的移动方向发生改变,所以changedirection 需要发生变动,更改为按键方向。
\# pygame 所有事件全部放到一个实时循环中
while True:
# 从队列中获取事件
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K\_RIGHT:
changedirection \= 'right'
if event.key == K\_LEFT:
changedirection \= 'left'
if event.key == K\_UP:
changedirection \= 'up'
if event.key == K\_DOWN:
changedirection \= 'down'
if event.key == K\_ESCAPE:
pygame.event.post(pygame.event.Event(QUIT))
蛇的移动方向由direction决定,按键改变的是changedirection,所以我们需要将changedirection的值赋予direction
众所周知,贪吃蛇是不可以走回头路的,也就是说当贪吃蛇向右移动,按左键是没哟效果的
所以在将changedirection的值赋予direction 之前 还需要判断两个值是否相反
\# 确定方向
if changedirection == 'left' and not direction == 'right':
direction \= changedirection
if changedirection == 'right' and not direction == 'left':
direction \= changedirection
if changedirection == 'up' and not direction == 'down':
direction \= changedirection
if changedirection == 'down' and not direction == 'up':
direction \= changedirection
4.5贪吃蛇转弯
就像上文提到的那样,蛇身是跟着蛇头运动,所以转弯实际上是改变蛇头的位置。
将蛇身与蛇头分开来写相对来说这时候比较占优势,只要改变蛇头snake_head的位置信息就可以。
并不是说蛇头和蛇身必须分开写,也可以放在一起,我们只需要多写一步 提取蛇的第一个方块信息就可以了
那么问题来了,怎么改变蛇头位置信息才能达到转弯的效果?
我们以蛇在向右移动,这时按↓键为例
蛇头这时候应当向下移动一个方块的位置,也就是说这时候蛇头的“X”不发生改变,“Y”值增加一个方块的数值,也就是20
同理可得蛇头向上等操作的方法,注意snake_head是一个数组 ,snake_head[0]即为“X” snake_head[1]即为“Y”
代码如下
\# 根据方向移动蛇头
if direction == 'right':
snake\_head\[0\] += 20
if direction == 'left':
snake\_head\[0\] -= 20
if direction == 'up':
snake\_head\[1\] -= 20
if direction == 'down':
snake\_head\[1\] += 20
4.5贪吃蛇吃方块
贪吃蛇游戏的目的便是控制贪吃蛇“吃”掉方块儿,那么怎样来实现呢?
首先蛇的嘴巴长在蛇头上,所以蛇吃掉方块需要用到蛇头的位置信息。
其次目标方块儿存放在指定位置,所以当蛇头的位置信息等于目标方块儿的位置信息即可
位置信息包含x与y,所以当蛇头x=目标方块儿x,并且蛇头y=目标方块儿y时,我们便认定贪吃蛇吃了方块
之前设定判断目标方块的状态变量 targetflag便起到作用,1表示没吃,0表示吃了,所以targetflag从1变成了0
\# 如果贪吃蛇位置和目标方块位置重合
if snake\_head\[0\] == targetPosition\[0\] and
snake\_head\[1\] == targetPosition\[1\]:
targetFlag \= 0
else:
snake\_body.pop()
4.6重新生成新的目标方块
当判断目标方块儿被吃了,也就是说targetflag=0时,系统需要重新生成一个新的目标方块。
目标方块的设定相对来说比较简单,只需要生成一个新的位置信息并将targetflag=1即可。
目标方块将会出现在一个随机的位置,所以我们在这里需要引入一个随机数,这也是为什么刚开始开发游戏时,需要import random
由于一个方块的大小为20*20,游戏界面为640*480,所以x的取值范围只有(20/20, 640/20)即为(1, 32)
同理可得y的取值范围应当是(1,24) 所以随机生成的目标方块儿位置信息应当为(x*20, y*20)
输入的位置信息应当为整数类型,所以还需要加强转,代码如下
if targetFlag == 0:
x \= random.randrange(1, 32)
y \= random.randrange(1, 24)
targetPosition \= \[int(x \* 20), int(y \* 20)\]
targetFlag \= 1
5.界面生成
写到这里,游戏的规则基本完成,接下来我们需要“画”出我们的界面
首先给自己的游戏界面填充为黑色,借用playSurface.fill()函数,将黑色的参数传入
之后就是画我们的贪吃蛇,用for循环画每一部分的身子,利用pygame中draw所带的Rect函数来绘画方块 rect函数需要传四个参数
第一个为surface,需要制定一个surface编辑区域
第二个为color,即绘画的颜色,这个很好理解
第三个为rect,rect为绘画矩形,需要提供矩形的位置,长度,宽度
第四个为width,这并不代表宽度,而是特指线条的粗细, width=0实心,width=1空心 ,一般可以不传入,默认为0
然后便是画目标方块,原理如上所示,但不需要用到for循环,毕竟就一个目标方块儿
最后开启实时更新界面
# 填充背景颜色
playSurface.fill(blackColor)
for position in snake\_body:
# rect函数内
# 第一个参数surface 指定一个surface编辑区
# 第二个参数color 指定颜色
# 第三个参数rect 返回一个矩形包含位置信息(x,y),(width,height)
# 第四个参数width 表示线条的粗细 width\=0 实心 width=1 空心
# 画蛇
pygame.draw.rect(playSurface, whiteColor, Rect(position\[0\], position\[1\], 20, 20))
# 画目标方块儿
pygame.draw.rect(playSurface, redColor, Rect(targetPosition\[0\], targetPosition\[1\], 20, 20))
# 更新显示到屏幕
pygame.display.flip()
6.游戏结束条件
当贪吃蛇撞击到边界时便会触发游戏结束,也就是蛇头的位置超过了预定的640*480的界面,这时候游戏结束
\# 判断游戏结束
if snake\_head\[0\] > 620 or snake\_head\[0\] < 0:
gameOver()
if snake\_head\[1\] > 460 or snake\_head\[1\] < 0:
gameOver()
7.调控难度
调控难度主要是更改贪吃蛇的速度,之前有设定贪吃蛇速度的变量,这时候我们只要加以修改即可,个人比较手残,开三挡即可,有兴趣的小伙伴可以尝试下更高的难度
\# 控制游戏速度
fpsClock.tick(3)
8.开启游戏,启动main函数
\# 启动入口 main函数
if \_\_name\_\_ == '\_\_main\_\_':
main()
至此就开发完成了一个简单的像素贪吃蛇,下面便是游戏最终效果
由于种种原因,最后有些地方没来得及改进,所以也算给诸位留下一些难题。
过段时间我会重新更新更加完善、更加丰富的贪吃蛇项目
改进方案:
1.可以加入分数体系,在每次吃到目标方块儿后分数加一,最终在结束后呈现给玩家
2.贪吃蛇游戏结束条件:蛇头碰到自己身体,游戏结束未实现
3.界面过于简单,可以制作一个简单的游戏开始界面,或者在游戏结束后创建一个排名榜,重来一次等
4.部分代码跨度较大 显得冗长,建议精简重新构建框架
最后显示源代码,以供各位参考
\# python 运行时的环境
import pygame, sys, random
# 这个模块包含所有pygame所使用的常量
from pygame.locals import \*
# 定义颜色变量
# 目标方块儿红颜色
redColor \= pygame.Color(255, 0, 0)
# 背景颜色为黑色
blackColor \= pygame.Color(0, 0, 0)
# 蛇颜色为白色
whiteColor \= pygame.Color(255, 255, 255)
# 定义游戏结束
def gameOver():
pygame.quit()
sys.exit()
# 定义main函数 定义入口函数
def main():
# 初始化pygame
pygame.init()
# 定义一个变量 控制速度
fpsClock \= pygame.time.Clock()
# 创建一个窗口界面
playSurface \= pygame.display.set\_mode((640, 480))
pygame.display.set\_caption('贪吃蛇')
# 初始化目标方块的位置
targetPosition \= \[300, 300\]
# 目标方块标记 判断贪吃蛇是否吃掉目标方块 1为没吃掉 0为吃掉
targetFlag \= 1
# 初始化贪吃蛇的位置 (100,100)为基准
# 初始化贪吃蛇长度 列表中有几个元素 就有几个身体
snake\_head \= \[100, 100\]
snake\_body \= \[\[80, 100\], \[60, 100\]\]
# 初始化方向 默认为右
direction \= 'right'
# 定义一个认为控制的方向的变量
changedirection \= direction
# pygame 所有事件全部放到一个实时循环中
while True:
# 从队列中获取事件
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K\_RIGHT:
changedirection \= 'right'
if event.key == K\_LEFT:
changedirection \= 'left'
if event.key == K\_UP:
changedirection \= 'up'
if event.key == K\_DOWN:
changedirection \= 'down'
if event.key == K\_ESCAPE:
pygame.event.post(pygame.event.Event(QUIT))
# 确定方向
if changedirection == 'left' and not direction == 'right':
direction \= changedirection
if changedirection == 'right' and not direction == 'left':
direction \= changedirection
if changedirection == 'up' and not direction == 'down':
direction \= changedirection
if changedirection == 'down' and not direction == 'up':
direction \= changedirection
# 根据方向移动蛇头
if direction == 'right':
snake\_head\[0\] += 20
if direction == 'left':
snake\_head\[0\] -= 20
if direction == 'up':
snake\_head\[1\] -= 20
if direction == 'down':
snake\_head\[1\] += 20
# 增加蛇的长度
snake\_body.insert(0, list(snake\_head))
# 如果贪吃蛇位置和目标方块位置重合
if snake\_head\[0\] == targetPosition\[0\] and snake\_head\[1\] == targetPosition\[1\]:
targetFlag \= 0
else:
snake\_body.pop()
if targetFlag == 0:
x \= random.randrange(1, 32)
y \= random.randrange(1, 24)
targetPosition \= \[int(x \* 20), int(y \* 20)\]
targetFlag \= 1
# 填充背景颜色
playSurface.fill(blackColor)
for position in snake\_body:
# rect函数内
# 第一个参数surface 指定一个surface编辑区
# 第二个参数color 指定颜色
# 第三个参数rect 返回一个矩形包含位置信息(x,y),(width,height)
# 第四个参数width 表示线条的粗细 width\=0 实心 width=1 空心
# 画蛇
pygame.draw.rect(playSurface, whiteColor, Rect(position\[0\], position\[1\], 20, 20))
# 画目标方块儿
pygame.draw.rect(playSurface, redColor, Rect(targetPosition\[0\], targetPosition\[1\], 20, 20))
# 更新显示到屏幕
pygame.display.flip()
# 判断游戏结束
if snake\_head\[0\] > 620 or snake\_head\[0\] < 0:
gameOver()
if snake\_head\[1\] > 460 or snake\_head\[1\] < 0:
gameOver()
# 控制游戏速度
fpsClock.tick(3)
# 启动入口 main函数
if \_\_name\_\_ == '\_\_main\_\_':
main()