今天我将向大家介绍如何使用 Python 编写一个贪吃蛇游戏。在这个游戏中,你将控制食物的位置,而蛇会自动追逐食物。这将让你更好地理解 Python 编程以及贪吃蛇游戏的实现过程。
首先,我们需要导入一些必要的库,如 random、collections 和 blessed。然后,我们创建一个 Terminal 对象来控制终端,并定义一些常量,如方向、移动方式、边界、身体、头部和食物等。
接下来,我们定义了蛇的初始位置,并使用双向队列(deque)来存储蛇的身体部分。我们还定义了食物的初始位置,并设置了窗口大小、分数和速度等参数。
在这个游戏中,我们通过控制食物的位置来影响蛇的行动。我们使用列表来存储空位置,以便在需要时放置食物。然后,我们使用 with 语句创建一个循环,用于更新游戏状态并重新绘制窗口。
在游戏过程中,蛇的速度和体长会随着时间的推移而变化。我们通过定义循环轮数(turn)来实现这一点,并通过取余的方式增加速度。同时,我们还定义了一个变量(M),用于表示蛇体长的最大值。
最后,我们使用一个 with 语句来绘制游戏界面。我们首先清理屏幕,然后创建一个二维的“world”列表,表示游戏的世界。我们还绘制了竖线和横线,以便更好地显示游戏界面。
接下来,让我们一起来看看这段贪吃蛇代码的实现过程,探索食物对蛇的诱惑力如何在代码中体现。如下图所示
贪吃蛇
篇幅有限,部分代码展示
完整代码参考原文链接
贪吃蛇的奥秘:食物诱惑力如何在代码中体现
"""
控制食物
1.我们控制的是食物,而不是蛇
2.让蛇可以自动的加速
3.让蛇的身体可以自动的变长
4.蛇的大体移动方向是食物所在的方向
"""import random
import copy
from collections import dequefrom blessed import Terminal# 创建terminal对象 控制终端
term = Terminal()
# 定义获取键盘
UP = term.KEY_UP
RIGHT = term.KEY_RIGHT
LEFT = term.KEY_LEFT
DOWN = term.DOWN
direction = RIGHT #定义初始方向
# 定义变量,字典类型 存储数据
MOVEMENT_MAP = {LEFT: [0, -1], UP: [-1, 0], RIGHT: [0, 1], DOWN: [1, 0]}
# 添加状态,活着
dead = False
# 定于框内元素
BORDER = '-'
BODY = '*'
HEAD = '#'
APPLE = 'x'
SPACE = ' '# 定义蛇,初始化蛇的初始位置,双向队列,使用 deque(双向队列)来实现蛇的移动,其中每个元素表示蛇的一个身体部分,
# 例如 [6, 5] 表示蛇的一个身体部分位于第 6 行第 5 列。
snake = deque([[6, 5], [6, 4], [6, 3]])
# 定义食物的位置
food = [5, 10]# 定义窗口大小
h, w = 10, 15
# 定义分数
score = 0
# 定义速度
speed = 3
MAX_SPEED = 6# 自动》变量》循环轮数实现蛇的速度和体长变化
# turn 表示循环的轮数,循环越多,通过取余的方式增加速度,turn -> turn %N2 < N1 -> speed = speed * 1.07N1 = 1
N2 = 2
# turn % M==0 增长蛇的体长
M = 9# 定义方法 获取空位置放食物
# 收集 world 二维
# 组中为空的元系到 list 中
def list_empty_spaces(world, space):res = []for i in range(len(world)):for j in range(len(world[i])):if world[i][j] == space:res.append([i,j])return res# 绘制窗口,使用 with 语句创建一个循环,用于更新游戏状态并重新绘制窗口
# """
# "term.cbreak()" 是设置终端的 "cursor invisible" 属性,使终端的光标不可见。
# "term.hidden_cursor()" 是设置终端的 "cursor hidden" 属性,使终端的光标隐藏。
# """
with term.cbreak(), term.hidden_cursor():print(term.home + term.clear) #清理屏幕world = [[SPACE] * w for _ in range(h)]# 绘制竖线,创建一个二维的 "world" 列表,表示游戏的世界。它有 h 行 w 列for i in range(h):world[i][0] = BORDERworld[i][-1] = BORDER# 绘制横线for i in range(w):world[0][i] = BORDERworld[-1][i] = BORDER"""首先遍历蛇(snake)的每一个位置,遍历蛇的所有位置。s 是蛇的一个位置,例如 (1, 2)。并将蛇身的每个单元格设置为 "body""""for s in snake:world[s[0]][s[1]] = BODYhead = snake[0]world[head[0]][head[1]] = HEADworld[food[0]][food[1]] = APPLEfor row in world:print(''.join(str(x) for x in row))# 控制键盘移动逻辑val = '' # 定义一个空字符串moving = False # 判断是否移动turn = 0 #当前游戏轮数 循环次数while val.lower() != 'q': # quit# 阻塞val = term.inkey(timeout= 1 / speed) #if val.code in [UP,DOWN,RIGHT,LEFT]:moving = Trueif not moving:continue# 控制蛇想移动方向,计算蛇头和食物的距离判断方向head = snake[0]y_diff = food[0] - head[0]x_diff = food[1] - head[1]# 蛇希望移动的方向want_move = Noneif abs(y_diff)>abs(x_diff): # 获取差的绝对值 向上或向下移动if y_diff <= 0: # 向上移动want_move = UPelse:want_move = DOWNelse:if x_diff <= 0:want_move = LEFTelse:want_move = RIGHT# 计算出的可移动选择want_moves = [want_move] + [UP,DOWN,LEFT,RIGHT]# 定义具体要移动的位置next_move = Nonefor move in want_moves: # 循环movement = MOVEMENT_MAP.get(move)
# 浅拷贝获得头head_copy = copy.copy(head)# 对头部运算,移动蛇头head_copy[0] += movement[0]head_copy[1] += movement[1]# 获得移动位置之后的原本内容heading = world[head_copy[0]][head_copy[1]]if heading == BORDER: # 如果移到墙那里就会死掉continueelif heading == BODY: # 如果移到身体那里就会死掉if head_copy == snake[-1] and turn % M != 0:next_move = head_copybreakelse:continueelse:next_move = head_copybreak