相信我们绝大多数的人都玩过贪吃蛇这款游戏
今天我们就用python制作这款游戏
但是首先我们想做它就得弄明白他的实现原理是什么
首先我们要做的这款游戏界面是很low的,因为我们做的这款游戏算是最简单最入门的一款游戏
玩过这个游戏的人都很清楚,这个蛇在行走时的每一个格子都会移动到他前一个格子的位置,类似于这样一个一个跟随着往前走,最前面的那个格子是跟随着脑袋也就是蛇头往前走,头跟着你的控制器的方向走,这就实现了一个移动跟随
因为是贪吃蛇所以他要吃东西,当它的头部碰到了食物之后也就是头和食物重合了,他的尾部就会增加一格,这就是一个进食的过程 本人灵魂画师请不要介意
其实这就是这个游戏的核心思想,就干了这么两件事
pygame 下载地址
废话不多说,直接动手
第一步 导入模块
第二步 初始化框架
因为宽和高要经常用到,所以把它存在一个变量里面
在我们set_mode的同时会给我们创建一个window对象,我们就可以拿着window对象去显示了
set_caption设置标题
现在运行就会有个一闪而过的窗口
下面的们的代码会解决这个问题
我们代码最重要的部分 游戏循环
这个循环要一直循环下去,但是不能让他变成死循环
怎么解决这个问题呢,首先,这个游戏是可以结束的,结束的条件就是当用户点击退出或者是操作的蛇撞死的时候,这个循环就可以停了
所以我们可以设置一个变量quit=False,让他一直是false,循环应该结束的时候变成True
其次我们不能让这个循环一直不停的跑,我们要留出时间来去做一些游戏的渲染或者其他的一些工作,这些工作都是交给系统的,这里我们会用到pygame里面的time.Clock() 这个就是游戏的时间控制,比如把这个游戏调成多少帧
现在已经可以出现一个这样的窗口了
接下来我们还要处理游戏的一些事件和渲染
我们第一个要处理的事件就是游戏的退出
pygame.event.get()是获取到当前事件的队列
因为我们要处理这个队列的所有事件,
一般我们都会设置一个循环,就可以去处理内部一个一个的event
下面要做的就是渲染了,任何一个游戏都要有渲染的过程
pygame.draw.rect(window,)绘制工具,参数1要说明你要往哪画,参数2要说明你要画什么颜色的东西,参数三要说明你要画的范围,从哪开始到哪里结束
pygame.display.flip() #暂时把控制权交还给系统,让系统去做一些渲染操作
显示结果如下:(不要在意它的颜色)
现在已经完成了框架初始化的操作
第三步 绘制场景
可以把上面的场景看成一个相对较大的二维数组(学过numpy的同学应该很好理解)
类似于这样:0 0 0 0 0
0 2 1 1 0
0 0 0 1 1
1代表蛇 2代表食物 每个元素都有一个数据
现在我们需要把这个给体现出来:
先设置这个格子的行和列 行决定了它的纵向 列决定了它的左右位置 现在我们就得到了每个格子有多大 比如: 宽度=总宽度(width)/列(ROW)后面会有用
这里我弄一个Point对象,让每一个点是让行和列组成的
把点的行和列都保存起来 大致是这样一个功能
下面开始定义坐标:
先从蛇的头开始,蛇头其实就是一个point对象 我们让它的初始位置在正中间
然后再定义蛇的食物,因为蛇的食物是随机出现的,所以这里我们用到random模块
这里有个小细节,我们要生成食物并且不让食物生成在蛇的身体里面,我们可以定义一个函数去解决
下面开始下一步:
但是我们要计算坐标位置,在绘图中我们是不可以使用行和列的,我们获取到它的位置就要使用上下左右的间距,由此可以推算出左间距=clo*格子的width(可以画图仔细理解一波),上间距=row*格子的height
因为需要执行很多步画图操作 所以定义一个函数,这里其实是将方块涂色
下面我们就开始画蛇的部分:
下面是蛇的移动:
比如我们要朝左边,row不动,clo-=1 右边就是clo+=1 依次类推
我们可以先定义一个变量表示当前蛇移动的方向 再进行移动判断
这里还有一个小细节 就是当你在往左移动时,不能直接朝右边移动,朝上移动时,不能直接朝下,所以我们加了if判断
pygame.KEYDOWN 键盘摁下事件
event.key是每个键的编码,273->W 119->↑…
下面处理蛇的跟随移动:
我们可以吧坐标以元组的形式放入一个列表,每次移动头的位置会放对应的方向移动1格(吧原来的头插入到前面insert),并且尾部会消失pop(因为头往前移动了一格),其他不需要变动,只变动头和尾就可以
为了方便我们再给point对象添加一个方法 copy,在copy的过程中其实就是创建一个新的point,这样就可以复制他自己
但是如果蛇吃到食物之后,他是会增加一格的,所以我们这里判断一下,如果蛇头与食物重合,就说明蛇迟到了食物,没重合就说明没吃到这个食物,并且每次吃到这个食物,食物又会在随机位置出现
最后,我们要处理蛇撞到墙壁或者撞到自身之后游戏结束的操作,其实很简单,如果蛇头出现在了格子以外的地方或者蛇头与蛇的身体重合,就会视为游戏失败,随即会退出游戏
做到这里就告一段落了,其实这个游戏还有很多地方可以改进,比如添加一个计分系统、失败后出现重新开始按钮和开始时出现开始游戏按钮等等。。。如果有人需要的话我再后面会加以改进。
下面是源码
import pygame
from sys import exit
import random
class Point():
row = 0
clo = 0
def __init__(self, row, clo):
self.row = row
self.clo = clo
def copy(self):
return Point(row=self.row, clo=self.clo)
# 初始化
pygame.init()
width = 800
hight = 400
ROW = 30
CLO = 40
direct = 'left'
window = pygame.display.set_mode((width, hight))
pygame.display.set_caption('贪吃蛇游戏')
# 蛇头坐标定在中间
head = Point(row=int(ROW / 2), clo=int(CLO / 2))
# 初始化蛇身的元素数量
snake = [
Point(row=head.row, clo=head.clo + 1),
Point(row=head.row, clo=head.clo + 2),
Point(row=head.row, clo=head.clo + 3)
]
# 生成食物并且不让食物生成在蛇的身体里面
def gen_food():
while 1:
position = Point(row=random.randint(0, ROW - 1), clo=random.randint(0, CLO - 1))
is_coll = False
if head.row == position.row and head.clo == position.clo:
is_coll = True
for body in snake:
if body.row == position.row and body.clo == position.clo:
is_coll = True
break
if not is_coll:
break
return position
# 定义坐标
# 蛇头颜色可以自定义
head_color = (0, 158, 128)
# 食物坐标
snakeFood = gen_food()
# 食物颜色
snakeFood_color = (255, 255, 0)
snake_color = (200, 147, 158)
# 需要执行很多步画图操作 所以定义一个函数
def rect(point, color):
# 定位 画图需要left和top
left = point.clo * width / CLO
top = point.row * hight / ROW
# 将方块涂色
pygame.draw.rect(window, color, (left, top, width / CLO, hight / ROW))
quit = True
# 设置帧频率
clock = pygame.time.Clock()
while quit:
# 处理帧频 锁帧
clock.tick(30)
# pygame.event.get()获取当前事件的队列 可以同时发生很多事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit = False
elif event.type == pygame.KEYDOWN:
# 这里小细节蛇不可以直接左右上下 要判断当前是在什么状态下前行
if event.key == 273 or event.key == 119:
if direct == 'left' or direct == 'right':
direct = 'top'
if event.key == 274 or event.key == 115:
if direct == 'left' or direct == 'right':
direct = 'bottom'
if event.key == 276 or event.key == 97:
if direct == 'top' or direct == 'bottom':
direct = 'left'
if event.key == 275 or event.key == 100:
if direct == 'top' or direct == 'bottom':
direct = 'right'
# 吃东西
eat = (head.row == snakeFood.row and head.clo == snakeFood.clo)
# 处理蛇的身子
# 1.把原来的头插入到snake的头上
# 2.把最后一个snake删掉
if eat:
snakeFood = Point(row=random.randint(0, ROW - 1), clo=random.randint(0, CLO - 1))
snake.insert(0, head.copy())
if not eat:
snake.pop()
# 移动一下
if direct == 'left':
head.clo -= 1
if direct == 'right':
head.clo += 1
if direct == 'top':
head.row -= 1
if direct == 'bottom':
head.row += 1
dead = False
if head.clo < 0 or head.row < 0 or head.clo >= CLO or head.row >= ROW:
dead = True
for body in snake:
if head.clo == body.clo and head.row == body.row:
dead = True
break
if dead:
print('Game Over')
quit = False
# 背景画图
pygame.draw.rect(window, (245, 135, 155), (0, 0, width, hight))
# 蛇头
rect(head, head_color)
# 绘制食物
rect(snakeFood, snakeFood_color)
# 绘制蛇的身子
for body in snake:
rect(body, snake_color)
# 交还控制权
pygame.display.flip()
希望此文章对你有所帮助,最后谢谢阅读