Computer Vision Snake Game
All about how to implement snake game using computer vision.
import random
import cvzone
import math
import cv2
import numpy as np
from cvzone.HandTrackingModule import HandDetector
Logic of the game
- First, we detect the index finger point of the hand using CVzone package and extract it.
- Then we initialize the list to store all points, list to store all distances between points, create variable to store current length, variable to store allowed distance which is 150 in our case and we set a previousHead variable as 0,0 for previous head position.
- Now we create a SarpaGame Class for creating a game where we have initialized above mentioned list and variables.
-
Then we create a update method where we write all the logic of the game. Lets learn step by step :
- First we check if the game is over or not. If not then we initialized the previous head points and current head points and we calculate the distance between them. and append the result in length list.
-
Then we update the update the current length position and previous head position.
-
Now we have to reduce the length since it keep increasing infinitely so which is not desirable.So we check the condition whether our snake length is in range of desired length or not.If not then we reduce the length of the snake by popping out certain number of elements from the list.
-
We will draw the snake if there is points by giving input to the cv2.line function as a previous points and current points.
-
Now we will draw a food in the screen by overlaying donut image on the screen by using cvzone package.
-
Now checking if the food is eaten by snake. For that we will create function to generate random food position using randomFoodLocation methods which will give us a random position. Now we will create a logic that if our index is at a correct position we declare it as a eaten.
-
Finally we will check whether their is collision or not. Here we will give the points to our cv2.polylines function to draw the snake and calculate the minimum distance using cv2.pointPolygonTest function. After this we will check if the distance is in our range if not print hit.
cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)
detector = HandDetector(detectionCon=0.8, maxHands=1)
class SarpaGame:
def __init__(self, pathFood):
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.previousHead = 0, 0 # previous head point
self.imgFood = cv2.imread(pathFood, cv2.IMREAD_UNCHANGED)
self.hFood, self.wFood, _ = self.imgFood.shape
self.foodPoint = 0, 0
self.randomFoodLocation()
self.score = 0
self.gameOver = False
def randomFoodLocation(self):
self.foodPoint = random.randint(100, 1000), random.randint(100, 600)
def update(self, imgMain, currentHead):
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:
px, py = self.previousHead
cx, cy = currentHead
self.points.append([cx, cy])
distance = math.hypot(cx - px, cy - py)
self.lengths.append(distance)
self.currentLength += distance
self.previousHead = cx, cy
# 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)
# Draw Food
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.previousHead = 0, 0 # previous head point
self.randomFoodLocation()
return imgMain
game = SarpaGame("./Donut.png")
while True:
success, img = cap.read()
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