0、项目介绍

1、效果展示

2、项目搭建

3、项目代码展示与讲解

4、项目资源

5、项目总结

# 2、项目搭建

————17 Gluttonous snake

——Donut.png

——snake.py

# 3、项目代码展示与讲解

``````#snake.py

import math
import random
import cvzone
import cv2
import numpy as np
from cvzone.HandTrackingModule import HandDetector

cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)

detector = HandDetector(detectionCon=0.8, maxHands=1)

class SnakeGameClass:
def __init__(self, pathFood):
self.points = []  # 蛇的所有点
self.lengths = []  # 每个点之间的距离
self.currentLength = 0  # 蛇的总长度
self.allowedLength = 150  # 总共允许长度
self.previousHead = 0, 0  # 起点

self.hFood, self.wFood, _ = self.imgFood.shape  # 得到甜甜圈图像的长、宽
self.foodPoint = 0, 0  # 初始化甜甜圈的位置

self.randomFoodLocation()  # 随机分布甜甜圈的位置

self.score = 0  # 吃得甜甜圈的分数
self.gameOver = False # gameover

def randomFoodLocation(self):
self.foodPoint = random.randint(100, 1000), random.randint(100, 600)

if self.gameOver:
cvzone.putTextRect(imgMain, "Game Over", [300, 400],
scale=7, thickness=5, offset=20)
cvzone.putTextRect(imgMain, f'Your Score: {self.score}', [300, 550],
scale=7, thickness=5, offset=20)
else:

self.points.append([cx, cy])
distance = math.hypot(cx - px, cy - py)
self.lengths.append(distance)
self.currentLength += distance

# Length Reduction
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

# Check if snake ate the Food
rx, ry = self.foodPoint
if rx - self.wFood // 2 < cx < rx + self.wFood // 2 and
ry - self.hFood // 2 < cy < ry + self.hFood // 2:
self.randomFoodLocation()
self.allowedLength += 50
self.score += 1
print(self.score)

# Draw Snake
if self.points:
for i, point in enumerate(self.points):
if i != 0:
cv2.line(imgMain, self.points[i - 1], self.points[i], (0, 0, 255), 20)
cv2.circle(imgMain, self.points[-1], 20, (0, 255, 0), cv2.FILLED)

imgMain = cvzone.overlayPNG(imgMain, self.imgFood,
(rx - self.wFood // 2, ry - self.hFood // 2))

cvzone.putTextRect(imgMain, f'Score: {self.score}', [50, 80],
scale=3, thickness=3, offset=10)

# Check for Collision
pts = np.array(self.points[:-2], np.int32)
pts = pts.reshape((-1, 1, 2))
cv2.polylines(imgMain, [pts], False, (0, 255, 0), 3)
minDist = cv2.pointPolygonTest(pts, (cx, cy), True)

if -1 <= minDist <= 1:
print("Hit")
self.gameOver = True
self.points = []  # all points of the snake
self.lengths = []  # distance between each point
self.currentLength = 0  # total length of the snake
self.allowedLength = 150  # total allowed Length
self.randomFoodLocation()

return imgMain

game = SnakeGameClass("Donut.png")

while True:
img = cv2.flip(img, 1)
hands, img = detector.findHands(img, flipType=False)

if hands:
lmList = hands[0]['lmList']
pointIndex = lmList[8][0:2]
img = game.update(img, pointIndex)
cv2.imshow("Image", img)
key = cv2.waitKey(1)
if key == ord('r'):

game.gameOver = False

elif key==27:break``````

• Length Reduction：

一旦蛇的总长度超过了我们允许的长度，我们就需要对其进行缩减，这里使用了enumerate函数对列表进行了迭代，返回了一个索引和值，方便减去对应的距离。

• Check if snake ate the Food：

只要蛇头进入了甜甜圈的范围内，即可认为是吃到了甜甜圈，接下来就可以完成食物位置的更新，蛇身的加长，score得分。

• Draw Snake：

画蛇的初始态。

在窗口画面中覆盖上甜甜圈，可以使用cvzone.overlayPNG函数。

• Check for Collision：

[pts]为多边形曲线阵列，在这里我们将会绘制一个多边形，并用cv2.pointPolygonTest来返回除最后两个点外与蛇头最近的距离，因为有tickness的原因，所以我们无需纠结于minDist一定小于等于0。

# 4、项目资源

GitHub:17 Gluttonous snake

THE END