使用Python+OpenCV代码制作贪吃蛇小游戏,你也可以打造自己的AI
yund56 2025-05-09 10:01 52 浏览
前言
今天和大家分享一下如何使用 mediapipe+opencv 自制贪吃蛇小游戏。先放张图看效果。
规则:食指指尖控制蛇头,指尖每接触到黄色方块,计数加一,蛇身变长,方块随机切换位置。如果指尖停止移动,或者移动过程中蛇头撞到蛇身,那么游戏结束。点击键盘上的R键重新开始游戏。
游戏进行时:
游戏结束界面:
1. 安装工具包
pip install opencv_python==4.2.0.34 # 安装opencv
pip install mediapipe # 安装mediapipe
# pip install mediapipe --user #有user报错的话试试这个
pip install cvzone # 安装cvzone
# 导入工具包
import cv2
import cvzone
import numpy as np
from cvzone.HandTrackingModule import HandDetector # 导入手部检测模块
import math
import random21个手部关键点信息如下,本节我们主要研究食指指尖'8'的坐标(x,y)信息。
2. 检测手部关键点
(1)
cvzone.HandTrackingModule.HandDetector()是手部关键点检测方法
参数:
mode: 默认为 False,将输入图像视为视频流。它将尝试在第一个输入图像中检测手,并在成功检测后进一步定位手的坐标。在随后的图像中,一旦检测到所有 maxHands 手并定位了相应的手的坐标,它就会跟踪这些坐标,而不会调用另一个检测,直到它失去对任何一只手的跟踪。这减少了延迟,非常适合处理视频帧。如果设置为 True,则在每个输入图像上运行手部检测,用于处理一批静态的、可能不相关的图像。
maxHands: 最多检测几只手,默认为 2
detectionCon: 手部检测模型的最小值(0-1之间),超过阈值则检测成功。默认为 0.5
minTrackingCon: 坐标跟踪模型的最小置信值 (0-1之间),用于将手部坐标视为成功跟踪,不成功则在下一个输入图像上自动调用手部检测。将其设置为更高的值可以提高解决方案的稳健性,但代价是更高的延迟。如果 mode 为 True,则忽略这个参数,手部检测将在每个图像上运行。默认为 0.5
它的参数和返回值类似于官方函数 mediapipe.solutions.hands.Hands()
MULTI_HAND_LANDMARKS: 被检测/跟踪的手的集合,其中每只手被表示为21个手部地标的列表,每个地标由x, y, z组成。x和y分别由图像的宽度和高度归一化为[0,1]。Z表示地标深度。
MULTI_HANDEDNESS: 被检测/追踪的手是左手还是右手的集合。每只手由label(标签)和score(分数)组成。 label 是 'Left' 或 'Right' 值得字符串。 score 是预测左右手的估计概率。
(2)cvzone.HandTrackingModule.HandDetector.findHands()找到手部关键点并绘图
参数:
img: 需要检测关键点的帧图像,格式为BGR
draw: 是否需要在原图像上绘制关键点及识别框
flipType: 图像是否需要翻转,当视频图像和我们自己不是镜像关系时,设为True就可以了
返回值:
hands: 检测到的手部信息,由0或1或2个字典组成的列表。如果检测到两只手就是由两个字典组成的列表。字典中包含:21个关键点坐标(x,y,z),检测框左上坐标及其宽高,检测框中心点坐标,检测出是哪一只手。
img: 返回绘制了关键点及连线后的图像
代码如下:
import cv2
import cvzone
import numpy as np
from cvzone.HandTrackingModule import HandDetector # 导入手部检测模块
#(1)获取摄像头
cap = cv2.VideoCapture(0) # 0代表电脑自带的摄像头
# 设置显示窗口的size
cap.set(3, 1280) # 窗口宽1280
cap.set(4, 720) # 窗口高720
#(2)模型配置
detector = HandDetector(maxHands=1, # 最多检测1只手
detectionCon=0.8) # 最小检测置信度0.8
#(3)图像处理
while True:
# 每次读取一帧相机图像,返回是否读取成功success,读取的帧图像img
success, img = cap.read()
# 图像翻转,使图像和自己呈镜像关系
img = cv2.flip(img, 1) # 0代表上下翻转,1代表左右翻转
# 检测手部关键点。返回手部信息hands,绘制关键点后的图像img
hands, img = detector.findHands(img, flipType=False) # 由于上一行翻转过图像了,这里就不用翻转了
# 查看关键点信息
print(hands)
#(4)关键点处理
if hands: # 如果检测到手了,那就处理关键点
# 获得食指指尖坐标(x,y)
hand = hands[0] # 获取一只手的全部信息
lmList = hand['lmList'] # 获得这只手的21个关键点的坐标(x,y,z)
pointIndex = lmList[8][0:2] # 只获取食指指尖关键点的(x,y)坐标
# 以食指指尖为圆心画圈(圆心坐标是元组类型),半径为15,青色填充
cv2.circle(img, tuple(pointIndex), 15, (255,0,0), cv2.FILLED)
#(5)显示图像
cv2.imshow('img', img) # 输入图像显示窗口的名称及图像
# 每帧滞留1毫秒后消失,并且按下ESC键退出
if cv2.waitKey(1) & 0xFF == 27:
break
# 释放视频资源
cap.release()
cv2.destroyAllWindows()效果图如下:
打印手部关键点信息如下:
[{'lmList': [[1152, 675, 0], [1085, 693, -37], [1030, 698, -68], [1003, 698, -97], [1003, 679, -122], [1001, 511, -48], [1041, 546, -81], [1093, 608, -102], [1134, 652, -110], [1075, 484, -46], [1119, 534, -84], [1171, 605, -101], [1217, 659, -103], [1141, 481, -45], [1177, 529, -83], [1219, 590, -84], [1253, 642, -73], [1195, 494, -47], [1221, 521, -73], [1245, 566, -65], [1267, 602, -49]],
'bbox': (1001, 481, 266, 217),
'center': (1134, 589),
'type': 'Right'}]3. 蛇身移动
构造一个处理蛇身移动的类,要求在没吃食物时,蛇身保持固定的长度跟随食指指尖移动。
举个例子,如果当前的蛇身节点列表 self.points 包含 [a, b, c, d] 这四个节点,a节点代表蛇尾,d节点代表蛇头。在下一帧,食指指尖移动到 e 点,将 e 节点追加到蛇身节点列表中,那么现在的列表包含 [a, b, c, d, e] 节点,其中 e 节点为新的蛇头。
此时判断当前蛇身总长度 self.currentLength(列表中所有节点之间的长度之和)是否大于蛇身固定长度 self.allowedLength,保证在移动过程中蛇身长度不变。
如果当前蛇身总长度 self.currentLength 大于固定长度 self.allowedLength,那么在节点列表中从尾到头依次删除节点,列表 [a, b, c, d, e] 中 a 表示蛇尾节点,先删除,判断列表 [b, c, d, e] 的节点之间的总长度是否满足要求。若仍大于固定长度,那么就再删除 b 节点,再判断。
如果当前蛇身总长度 self.currentLength 小于固定长度 self.allowedLength,那么就不做任何处理。
在上述代码中补充:
import cv2
import cvzone
import numpy as np
from cvzone.HandTrackingModule import HandDetector # 导入手部检测模块
import math
# 构造一个贪吃蛇移动的类
class SnakeGameClass:
#(一)初始化
def __init__(self):
self.points = [] # 蛇的身体的节点坐标
self.lengths = [] # 蛇身各个节点之间的坐标
self.currentLength = 0 # 当前蛇身长度
self.allowedLength = 150 # 没吃东西时,蛇的总长度
self.previousHead = (0,0) # 前一个蛇头节点的坐标
#(二)更新增加蛇身长度
def update(self, imgMain, currentHead): # 输入图像,当前蛇头的坐标
px, py = self.previousHead # 获得前一个蛇头的x和y坐标
cx, cy = currentHead # 当前蛇头节点的x和y坐标
# 添加当前蛇头的坐标到蛇身节点坐标列表中
self.points.append([cx,cy])
# 计算两个节点之间的距离
distance = math.hypot(cx-px, cy-py) # 计算平方和开根
# 将节点之间的距离添加到蛇身节点距离列表中
self.lengths.append(distance)
# 增加当前蛇身长度
self.currentLength += distance
# 更新蛇头坐标
self.previousHead = (cx,cy)
#(三)减少蛇尾长度,即移动过程中蛇头到蛇尾的长度不大于150
if self.currentLength > self.allowedLength:
# 遍历所有的节点线段长度。新更新的蛇头索引在列表后面,蛇尾的索引在列表前面
for i, length in enumerate(self.lengths):
# 从蛇尾到蛇头依次减线段长度,得到的长度是否满足要求
self.currentLength -= length
# 从列表中删除蛇尾端的线段长度,以及蛇尾节点
self.lengths.pop(i)
self.points.pop(i)
# 如果当前蛇身长度小于规定长度,满足要求,退出循环
if self.currentLength < self.allowedLength:
break
#(四)绘制蛇
# 当节点列表中有值了,才能绘制
if self.points:
# 遍历蛇身节点坐标
for i, point in enumerate(self.points):
# 绘制前后两个节点之间的连线
if i != 0:
cv2.line(imgMain, tuple(self.points[i-1]), tuple(self.points[i]), (0,255,0), 20)
# 在蛇头的位置画个圆
cv2.circle(imgMain, tuple(self.points[-1]), 20, (255,0,0), cv2.FILLED)
# 返回更新后的图像
return imgMain
#(1)获取摄像头
cap = cv2.VideoCapture(0) # 0代表电脑自带的摄像头
# 设置显示窗口的size
cap.set(3, 1280) # 窗口宽1280
cap.set(4, 720) # 窗口高720
#(2)模型配置
detector = HandDetector(maxHands=1, # 最多检测1只手
detectionCon=0.8) # 最小检测置信度0.8
# 接收创建贪吃蛇的类
game = SnakeGameClass()
#(3)图像处理
while True:
# 每次读取一帧相机图像,返回是否读取成功success,读取的帧图像img
success, img = cap.read()
# 图像翻转,使图像和自己呈镜像关系
img = cv2.flip(img, 1) # 0代表上下翻转,1代表左右翻转
# 检测手部关键点。返回手部信息hands,绘制关键点后的图像img
hands, img = detector.findHands(img, flipType=False) # 由于上一行翻转过图像了,这里就不用翻转了
# 查看关键点信息
print(hands)
#(4)关键点处理
if hands: # 如果检测到手了,那就处理关键点
# 获得食指指尖坐标(x,y)
hand = hands[0] # 获取一只手的全部信息
lmList = hand['lmList'] # 获得这只手的21个关键点的坐标(x,y,z)
pointIndex = lmList[8][0:2] # 只获取食指指尖关键点的(x,y)坐标
# 更新贪吃蛇的节点,给出蛇头节点坐标。返回更新后的图像
img = game.update(img, pointIndex)
#(5)显示图像
cv2.imshow('img', img) # 输入图像显示窗口的名称及图像
# 每帧滞留1毫秒后消失,并且按下ESC键退出
if cv2.waitKey(1) & 0xFF == 27:
break
# 释放视频资源
cap.release()
cv2.destroyAllWindows()效果图如下,蛇身保持默认固定长度随着指尖而移动。
4. 蛇进食增加身体长度
先看下面代码 SnakeGameClass 类中的第(五)步。给食物(即绘制的矩形)随机给出一个中心点坐标,自定义的类方法 randomFoodLocation(),执行该方法则食物的中心点坐标的x在[100,1000]中随机取一个数,y在[100,600]中随机取一个数。
下面代码定义的类中的第(七)步。判断食指指尖(即蛇头节点坐标)是否在矩形内部,如果在内部,那么蛇身移动过程中的固定长度 self.allowedLength 增加50个像素值。得分 self.score 加一。并在下一帧随机改变食物的位置。
在上述代码中补充:
import cv2
import cvzone
import numpy as np
from cvzone.HandTrackingModule import HandDetector # 导入手部检测模块
import math
import random
# 构造一个贪吃蛇移动的类
class SnakeGameClass:
#(一)初始化
def __init__(self):
self.score = 0 # 积分器
self.points = [] # 蛇的身体的节点坐标
self.lengths = [] # 蛇身各个节点之间的坐标
self.currentLength = 0 # 当前蛇身长度
self.allowedLength = 150 # 没吃东西时,蛇的总长度
self.previousHead = (0,0) # 前一个蛇头节点的坐标
self.foodPoint = (0,0) # 食物的起始位置
self.randomFoodLocation() # 随机改变食物的位置
#(五)食物随机出现的位置
def randomFoodLocation(self):
# x在100至1000之间,y在100至600之间,随机取一个整数
self.foodPoint = random.randint(100, 1000), random.randint(100, 600)
#(二)更新增加蛇身长度
def update(self, imgMain, currentHead): # 输入图像,当前蛇头的坐标
px, py = self.previousHead # 获得前一个蛇头的x和y坐标
cx, cy = currentHead # 当前蛇头节点的x和y坐标
# 添加当前蛇头的坐标到蛇身节点坐标列表中
self.points.append([cx,cy])
# 计算两个节点之间的距离
distance = math.hypot(cx-px, cy-py) # 计算平方和开根
# 将节点之间的距离添加到蛇身节点距离列表中
self.lengths.append(distance)
# 增加当前蛇身长度
self.currentLength += distance
# 更新蛇头坐标
self.previousHead = (cx,cy)
#(三)减少蛇尾长度,即移动过程中蛇头到蛇尾的长度不大于150
if self.currentLength > self.allowedLength:
# 遍历所有的节点线段长度。新更新的蛇头索引在列表后面,蛇尾的索引在列表前面
for i, length in enumerate(self.lengths):
# 从蛇尾到蛇头依次减线段长度,得到的长度是否满足要求
self.currentLength -= length
# 从列表中删除蛇尾端的线段长度,以及蛇尾节点
self.lengths.pop(i)
self.points.pop(i)
# 如果当前蛇身长度小于规定长度,满足要求,退出循环
if self.currentLength < self.allowedLength:
break
#(七)检查蛇是否吃了食物
rx, ry = self.foodPoint # 得到食物的中心点坐标位置
# 绘制矩形作为蛇的食物
cv2.rectangle(imgMain, (rx-20, ry-20), (rx+20, ry+20), (255,255,0), cv2.FILLED)
cv2.rectangle(imgMain, (rx-20, ry-20), (rx+20, ry+20), (0,255,255), 5)
cv2.rectangle(imgMain, (rx-5, ry-5), (rx+5, ry+5), (0,0,255), cv2.FILLED)
# 检查指尖(即蛇头cx,cy)是否在矩形内部
if rx-20 < cx < rx+20 and ry-20< cy < ry+20:
# 随机更换食物的位置
self.randomFoodLocation()
# 增加蛇身的限制长度,每吃1个食物就能变长50
self.allowedLength += 50
# 吃食物的计数加一
self.score += 1
print('eat!', f'score:{self.score}')
#(四)绘制蛇
# 当节点列表中有值了,才能绘制
if self.points:
# 遍历蛇身节点坐标
for i, point in enumerate(self.points):
# 绘制前后两个节点之间的连线
if i != 0:
cv2.line(imgMain, tuple(self.points[i-1]), tuple(self.points[i]), (0,255,0), 20)
cv2.line(imgMain, tuple(self.points[i-1]), tuple(self.points[i]), (0,0,255), 15)
# 在蛇头的位置画个圆
cv2.circle(imgMain, tuple(self.points[-1]), 20, (255,255,0), cv2.FILLED)
cv2.circle(imgMain, tuple(self.points[-1]), 18, (255,0,0), 3)
cv2.circle(imgMain, tuple(self.points[-1]), 5, (0,0,0), cv2.FILLED)
# 返回更新后的图像
return imgMain
#(1)获取摄像头
cap = cv2.VideoCapture(0) # 0代表电脑自带的摄像头
# 设置显示窗口的size
cap.set(3, 1280) # 窗口宽1280
cap.set(4, 720) # 窗口高720
#(2)模型配置
detector = HandDetector(maxHands=1, # 最多检测1只手
detectionCon=0.8) # 最小检测置信度0.8
# 接收创建贪吃蛇的类
game = SnakeGameClass()
#(3)图像处理
while True:
# 每次读取一帧相机图像,返回是否读取成功success,读取的帧图像img
success, img = cap.read()
# 图像翻转,使图像和自己呈镜像关系
img = cv2.flip(img, 1) # 0代表上下翻转,1代表左右翻转
# 检测手部关键点。返回手部信息hands,绘制关键点后的图像img
hands, img = detector.findHands(img, flipType=False) # 由于上一行翻转过图像了,这里就不用翻转了
#(4)关键点处理
if hands: # 如果检测到手了,那就处理关键点
# 获得食指指尖坐标(x,y)
hand = hands[0] # 获取一只手的全部信息
lmList = hand['lmList'] # 获得这只手的21个关键点的坐标(x,y,z)
pointIndex = lmList[8][0:2] # 只获取食指指尖关键点的(x,y)坐标
# 更新贪吃蛇的节点,给出蛇头节点坐标。返回更新后的图像
img = game.update(img, pointIndex)
#(5)显示图像
cv2.imshow('img', img) # 输入图像显示窗口的名称及图像
# 每帧滞留1毫秒后消失,并且按下ESC键退出
if cv2.waitKey(1) & 0xFF == 27:
break
# 释放视频资源
cap.release()
cv2.destroyAllWindows()效果图如下:
5. 自身碰撞及界面的处理
先看到自定义类 SnakeGameClass 中的第(八)步,蛇身节点列表 self.points 中包含从蛇头到蛇尾的所有节点。如 [a, b, c, d, e] 节点,a 节点代表蛇尾,e 节点代表蛇头。这里我就粗糙地判断一下是否碰撞,如果大家有更好的判断方法可以改动这第(八)步。计算蛇头 e 节点到所有节点之间的距离,如果小于某个值就代表碰撞了,游戏结束 self.gameover = True
再看到自定义类中的第(三)步。如果游戏结束 self.gameover = True,那就在下一帧中绘制结算界面,不再执行蛇身移动程序。
再看到主程序中的第(5)步。其中 k == ord('r'),按下键盘上的 r 键来重新游戏。将所有蛇身变量初始化,并将 self.gameover = False,退出结算界面,使得下一帧能执行蛇身移动操作。
在上述代码中补充:
import cv2
import cvzone
from matplotlib.cbook import pts_to_midstep
import numpy as np
from cvzone.HandTrackingModule import HandDetector # 导入手部检测模块
import math
import random
# 构造一个贪吃蛇移动的类
class SnakeGameClass:
#(一)初始化
def __init__(self):
self.score = 0 # 积分器
self.points = [] # 蛇的身体的节点坐标
self.lengths = [] # 蛇身各个节点之间的坐标
self.currentLength = 0 # 当前蛇身长度
self.allowedLength = 150 # 没吃东西时,蛇的总长度
self.previousHead = (0,0) # 前一个蛇头节点的坐标
self.foodPoint = (0,0) # 食物的起始位置
self.randomFoodLocation() # 随机改变食物的位置
self.gameover = False # 蛇头撞到蛇身,变成True,游戏结束
#(二)食物随机出现的位置
def randomFoodLocation(self):
# x在100至1000之间,y在100至600之间,随机取一个整数
self.foodPoint = random.randint(100, 1000), random.randint(100, 600)
#(三)更新增加蛇身长度
def update(self, imgMain, currentHead): # 输入图像,当前蛇头的坐标
# 游戏结束,显示文本
if self.gameover:
cvzone.putTextRect(imgMain, 'GameOver', [400,300], 5, 3, colorR=(0,255,255), colorT=(0,0,255))
cvzone.putTextRect(imgMain, f'Score:{self.score}', [450,400], 5, 3, colorR=(255,255,0))
cvzone.putTextRect(imgMain, f"Press Key 'R' to Restart", [230,500], 4, 3, colorR=(0,255,0), colorT=(255,0,0))
else:
px, py = self.previousHead # 获得前一个蛇头的x和y坐标
cx, cy = currentHead # 当前蛇头节点的x和y坐标
# 添加当前蛇头的坐标到蛇身节点坐标列表中
self.points.append([cx,cy])
# 计算两个节点之间的距离
distance = math.hypot(cx-px, cy-py) # 计算平方和开根
# 将节点之间的距离添加到蛇身节点距离列表中
self.lengths.append(distance)
# 增加当前蛇身长度
self.currentLength += distance
# 更新蛇头坐标
self.previousHead = (cx,cy)
#(四)减少蛇尾长度,即移动过程中蛇头到蛇尾的长度不大于150
if self.currentLength > self.allowedLength:
# 遍历所有的节点线段长度。新更新的蛇头索引在列表后面,蛇尾的索引在列表前面
for i, length in enumerate(self.lengths):
# 从蛇尾到蛇头依次减线段长度,得到的长度是否满足要求
self.currentLength -= length
# 从列表中删除蛇尾端的线段长度,以及蛇尾节点
self.lengths.pop(i)
self.points.pop(i)
# 如果当前蛇身长度小于规定长度,满足要求,退出循环
if self.currentLength < self.allowedLength:
break
#(五)绘制得分板
cvzone.putTextRect(imgMain, f'Score:{self.score}', [50,80], 4, 3, colorR=(255,255,0))
#(六)检查蛇是否吃了食物
rx, ry = self.foodPoint # 得到食物的中心点坐标位置
# 绘制矩形作为蛇的食物
cv2.rectangle(imgMain, (rx-20, ry-20), (rx+20, ry+20), (255,255,0), cv2.FILLED)
cv2.rectangle(imgMain, (rx-20, ry-20), (rx+20, ry+20), (0,255,255), 5)
cv2.rectangle(imgMain, (rx-5, ry-5), (rx+5, ry+5), (0,0,255), cv2.FILLED)
# 检查指尖(即蛇头cx,cy)是否在矩形内部
if rx-20 < cx < rx+20 and ry-20< cy < ry+20:
# 随机更换食物的位置
self.randomFoodLocation()
# 增加蛇身的限制长度,每吃1个食物就能变长50
self.allowedLength += 50
# 吃食物的计数加一
self.score += 1
print('eat!', f'score:{self.score}')
#(七)绘制蛇
# 当节点列表中有值了,才能绘制
if self.points:
# 遍历蛇身节点坐标
for i, point in enumerate(self.points):
# 绘制前后两个节点之间的连线
if i != 0:
cv2.line(imgMain, tuple(self.points[i-1]), tuple(self.points[i]), (0,255,0), 20)
cv2.line(imgMain, tuple(self.points[i-1]), tuple(self.points[i]), (0,0,255), 15)
# 在蛇头的位置画个圆
cv2.circle(imgMain, tuple(self.points[-1]), 20, (255,255,0), cv2.FILLED)
cv2.circle(imgMain, tuple(self.points[-1]), 18, (255,0,0), 3)
cv2.circle(imgMain, tuple(self.points[-1]), 5, (0,0,0), cv2.FILLED)
#(八)检查蛇头碰撞到自身
for point in self.points[:-2]: # 不算蛇头到自身的距离
# 计算蛇头和每个节点之间的距离
dist = math.hypot(cx-point[0], cy-point[1])
# 如果距离小于1.8,那么就证明碰撞了
if dist < 1.8:
# 游戏结束
self.gameover = True
# 返回更新后的图像
return imgMain
#(1)获取摄像头
cap = cv2.VideoCapture(0) # 0代表电脑自带的摄像头
# 设置显示窗口的size
cap.set(3, 1280) # 窗口宽1280
cap.set(4, 720) # 窗口高720
#(2)模型配置
detector = HandDetector(maxHands=1, # 最多检测1只手
detectionCon=0.8) # 最小检测置信度0.8
# 接收创建贪吃蛇的类
game = SnakeGameClass()
#(3)图像处理
while True:
# 每次读取一帧相机图像,返回是否读取成功success,读取的帧图像img
success, img = cap.read()
# 图像翻转,使图像和自己呈镜像关系
img = cv2.flip(img, 1) # 0代表上下翻转,1代表左右翻转
# 检测手部关键点。返回手部信息hands,绘制关键点后的图像img
hands, img = detector.findHands(img, flipType=False) # 由于上一行翻转过图像了,这里就不用翻转了
#(4)关键点处理
if hands: # 如果检测到手了,那就处理关键点
# 获得食指指尖坐标(x,y)
hand = hands[0] # 获取一只手的全部信息
lmList = hand['lmList'] # 获得这只手的21个关键点的坐标(x,y,z)
pointIndex = lmList[8][0:2] # 只获取食指指尖关键点的(x,y)坐标
# 更新贪吃蛇的节点,给出蛇头节点坐标。返回更新后的图像
img = game.update(img, pointIndex)
#(5)显示图像
cv2.imshow('img', img) # 输入图像显示窗口的名称及图像
# 重新开始游戏
k = cv2.waitKey(1) # 每帧滞留1毫秒后消失
if k == ord('r'): # 键盘'r'键代表重新开始游戏
game.gameover = False
game.score = 0 # 积分器
game.points = [] # 蛇的身体的节点坐标
game.lengths = [] # 蛇身各个节点之间的坐标
game.currentLength = 0 # 当前蛇身长度
game.allowedLength = 150 # 没吃东西时,蛇的总长度
game.previousHead = (0,0) # 前一个蛇头节点的坐标
game.randomFoodLocation() # 随机改变食物的位置
if k & 0xFF == 27: # 键盘ESC键退出程序
break
# 释放视频资源
cap.release()
cv2.destroyAllWindows()效果图如下,在移动过程中,蛇头每碰到一个食物,蛇身就会变长,如果 停止移动 或 蛇头节点距离蛇身节点过近 就会结束游戏。
相关推荐
- SM小分队Girls on Top,女神战队少了f(x)?
-
这次由SM娱乐公司在冬季即将开演的smtown里,将公司的所有女团成员集结成了一个小分队project。第一位这是全面ACE的大姐成员权宝儿(BoA),出道二十年,在日本单人销量过千万,韩国国内200...
- 韩国女团 aespa 首场 VR 演唱会或暗示 Quest 3 将于 10 月推出
-
AmazeVR宣布将在十月份举办一场现场VR音乐会,观众将佩戴MetaQuest3进行体验。韩国女团aespa于2020年11月出道,此后在日本推出了三张金唱片,在韩国推出了...
- 韩网热议!女团aespa成员Giselle在长腿爱豆中真的是legend
-
身高163的Giselle,长腿傲人,身材比例绝了...
- 假唱而被骂爆的女团:IVE、NewJeans、aespa上榜
-
在韩国,其实K-pop偶像并不被认为是真正的歌手,因为偶像们必须兼备舞蹈能力、也经常透过对嘴来完成舞台。由于科技的日渐发达,也有许多网友会利用消音软体来验证K-pop偶像到底有没有开麦唱歌,导致假唱这...
- 新女团Aespa登时尚大片 四个少女四种style
-
来源:环球网
- 韩国女团aespa新歌MV曝光 画面梦幻造型超美
-
12月20日,韩国女团aespa翻唱曲《DreamsComeTrue》MV公开,视频中,她们的造型超美!WINTER背后长出一双梦幻般的翅膀。柳智敏笑容甜美。宁艺卓皮肤白皙。GISELLE五官精致...
- 女网友向拳头维权,自称是萨勒芬妮的原型?某韩国女团抄袭KDA
-
女英雄萨勒芬妮(Seraphine)是拳头在2020年推出的第五位新英雄,在还没有正式上线时就备受lsp玩家的关注,因为她实在是太可爱了。和其他新英雄不同的是,萨勒芬妮在没上线时就被拳头当成虚拟偶像来...
- 人气TOP女团是?INS粉丝数见分晓;TWICE成员为何在演唱会落泪?
-
现在的人气TOP女团是?INS粉丝数见分晓!现在爱豆和粉丝之间的交流方法变得多种多样,但是Instagram依然是主要的交流手段。很多粉丝根据粉丝数评价偶像的人气,拥有数百、数千万粉丝的组合作为全球偶...
- 韩国女团MVaespa Drama MV_韩国女团穿超短裙子跳舞
-
WelcometoDrama.Pleasefollow4ruleswhilewatchingtheDrama.·1)Lookbackimmediatelywhenyoufe...
- aespa师妹团今年将出道! SM职员亲口曝「新女团风格、人数」
-
记者刘宛欣/综合报导南韩造星工厂SM娱乐曾打造出东方神起、SUPERJUNIOR、少女时代、SHINee、EXO等传奇团体,近年推出的aespa、RIIZE更是双双成为新生代一线团体,深受大众与粉丝...
- 南韩最活跃的女团aespa,新专辑《Girls》即将发布,盘点昔日经典
-
女团aespa歌曲盘点,新专辑《Girls》即将发布,期待大火。明天也就是2022年的7月8号,aespa新专辑《Girls》即将发行。这是继首张专辑《Savage》之后,时隔19个月的第二张专辑,这...
- 章泽天女团aespa出席戛纳晚宴 宋康昊携新片亮相
-
搜狐娱乐讯(山今/文玄反影/图科明/视频)法国时间5月23日晚,女团aespa、宋康昊、章泽天等明星亮相戛纳晚宴。章泽天身姿优越。章泽天肩颈线优越。章泽天双臂纤细。章泽天仪态端正。女团aespa亮...
- Aespa舞台暴露身高比例,宁艺卓脸大,柳智敏有“TOP”相
-
作为SM公司最新女团aespa,初舞台《BlackMamba》公开,在初舞台里,看得出来SM公司是下了大功夫的,虽然之前SM公司新出的女团都有很长的先导片,但是aespa显然是有“特殊待遇”。运用了...
- AESPA女团成员柳智敏karina大美女
-
真队内速度最快最火达成队内首个且唯一两百万点赞五代男女团中输断层第一(图转自微博)...
- 对来学校演出的女团成员语言性骚扰?韩国这所男高的学生恶心透了
-
哕了……本月4日,景福男子高中相关人士称已经找到了在SNS中上传对aespa成员进行性骚扰文章的学生,并开始着手调查。2日,SM娱乐创始人李秀满的母校——景福高中迎来了建校101周年庆典活动。当天,S...
- 一周热门
- 最近发表
-
- SM小分队Girls on Top,女神战队少了f(x)?
- 韩国女团 aespa 首场 VR 演唱会或暗示 Quest 3 将于 10 月推出
- 韩网热议!女团aespa成员Giselle在长腿爱豆中真的是legend
- 假唱而被骂爆的女团:IVE、NewJeans、aespa上榜
- 新女团Aespa登时尚大片 四个少女四种style
- 韩国女团aespa新歌MV曝光 画面梦幻造型超美
- 女网友向拳头维权,自称是萨勒芬妮的原型?某韩国女团抄袭KDA
- 人气TOP女团是?INS粉丝数见分晓;TWICE成员为何在演唱会落泪?
- 韩国女团MVaespa Drama MV_韩国女团穿超短裙子跳舞
- aespa师妹团今年将出道! SM职员亲口曝「新女团风格、人数」
- 标签列表
-
- filter函数js (37)
- filter函数excel用不了 (73)
- 商城开发 (40)
- 影视网站免费源码最新版 (57)
- 影视资源api接口 (46)
- 网站留言板代码大全 (56)
- java版软件下载 (52)
- java教材电子课本下载 (48)
- 0基础编程从什么开始学 (50)
- java是用来干嘛的 (51)
- it入门应该学什么 (55)
- java线上课程 (55)
- 学java的软件叫什么软件 (38)
- 程序开发软件有哪些 (53)
- 软件培训 (59)
- 机器人编程代码大全 (50)
- 少儿编程教程免费 (45)
- 新代系统编程教学 (61)
- 共创世界编程网站 (38)
- 亲测源码 (36)
- 三角函数积分公式表 (35)
- 函数的表示方法 (34)
- 表格乘法的公式怎么设置 (34)
- sumif函数的例子 (34)
- 图片素材 (36)
