Maison > Article > développement back-end > Comment Python utilise la reconnaissance gestuelle pour implémenter le jeu Snake
Tout le monde connaît le jeu Snake, mais la vision par ordinateur peu connue + le jeu Snake apportera aux gens plus de participation et de fraîcheur. Ce projet utilise principalement la reconnaissance gestuelle pour. terminez le jeu simple de Snake. Dans ce jeu, l'ordinateur capture nos gestes à travers la caméra et détermine s'il doit bouger. Le joueur bouge sa main pour contrôler le serpent afin d'obtenir de la nourriture qui apparaît aléatoirement sur l'écran. Chaque fois qu'un aliment est obtenu, il compte pour un. point, et le score sera Add 1 et l'affichera à l'écran. Lorsque le joueur entre accidentellement en collision avec la tête et le corps du serpent pendant le fonctionnement, GameOver!
(1) Le problème gauche et droite de l'image
Parce que nous utilisons des gestes pour contrôler le mouvement du serpent, mais l'image de la caméra montre le point de vue des autres. , donc c'est exactement l'opposé de la conscience gauche et droite du joueur, nous devons donc retourner l'image lue par la caméra vers la gauche et la droite. En principe, la position des pixels gauche et droit est échangée, mais en Python, vous pouvez utiliser une fonction cv2.flip() pour réaliser un retournement de miroir.
(2) Le problème de la taille de l'écran de la caméra
Nous devons jouer à des jeux sur les images obtenues via la caméra. Par conséquent, si l'écran est trop petit, cela entraînera un espace de jeu insuffisant au début, nous pouvons prétraiter le. taille de l'écran et définissez-la sur une taille plus raisonnable, et l'image finale n'aura pas l'air à l'étroit lorsque vous jouerez à des jeux. La largeur et la hauteur de l'écran peuvent être définies via les fonctions cap.set(3, m) cap.set(4, n).
Il y aura également d'autres précautions dans ce projet, telles que la détermination des collisions, la détermination de l'acquisition de nourriture, etc. Je les présenterai plus tard dans le processus du projet.
3. Points clés de la mise en œuvre du jeu
import math import random import cvzone import cv2 import numpy as np from cvzone.HandTrackingModule import HandDetector
Dans ce projet, nous utilisons principalement les bibliothèques ci-dessus, parmi lesquelles la bibliothèque aléatoire est utilisée. sélectionnez des pixels pour placer des beignets de nourriture, utilisez la reconnaissance des mains dans cvzone pour détecter les gestes des joueurs, utilisez cv2 pour effectuer certaines opérations de base sur les images, et d'autres bibliothèques ont également leurs propres utilisations, qui seront présentées une par une plus tard.
2. Trouvez les points clés et marquez-les
#检测到第一个手,并标记手部位置 if hands: lmList = hands[0]['lmList'] pointIndex = lmList[8][0:2] #第八个坐标点的 x, y值,其中 z 值不被包括在里面 cv2.circle(img, pointIndex, 20, (200, 0, 200), cv2.FILLED) #在关键点处绘制一个圆点并进行填充(此处只是示范,后面会更改)
3. Créez une classe pour sauvegarder toutes les fonctions du jeu
class SnakeGameClass: def __init__(self, pathFood): self.points = [] #贪吃蛇身上所有点 self.lengths = [] #点与点之间的距离 self.currentLength = 0 #当下蛇的长度 self.allowedLength = 50 #最大允许长度(阈值) self.previousHead = 0, 0 #手部关键点之后的第一个点 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
4. Définir une fonction pour mettre à jour en permanence
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 #长度缩小 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 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) #使用线条绘制贪吃蛇 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) #检测是否碰撞 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 = [] #蛇身上所有的点 self.lengths = [] #不同点之间的距离 self.currentLength = 0 #当前蛇的长度 self.allowedLength = 50 #最大允许长度 self.previousHead = 0, 0 #先前的蛇的头部 self.randomFoodLocation() return imgMain
Dans cette fonction mise à jour, nous devons juger beaucoup de choses, comme par exemple si le serpent gourmand touche la nourriture (s'il touche la nourriture, nous devons augmenter la longueur du serpent et accumuler des scores), si la longueur actuelle dépasse la longueur maximale autorisée (il n'est pas nécessaire de modifier la longueur actuelle si elle est inférieure à la longueur maximale, mais si la longueur actuelle est supérieure à la longueur maximale, elle doit être raccourcie), si le serpent collisions (par La distance entre les nœuds clés détermine si le serpent est entré en collision. Si une collision se produit, entrez dans le module gameover. Sinon, continuez le jeu), etc., sont tous expliqués dans le code ci-dessus.
Principalement grâce à la classe définie ci-dessus, on peut réaliser le jeu du serpent actuel.
4. Code global
""" Author:XiaoMa CSDN Address:一马归一码 """ 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 = 50 #最大允许长度(阈值) self.previousHead = 0, 0 #手部关键点之后的第一个点 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 #长度缩小 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 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) #使用线条绘制贪吃蛇 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) #检测是否碰撞 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 = [] #蛇身上所有的点 self.lengths = [] #不同点之间的距离 self.currentLength = 0 #当前蛇的长度 self.allowedLength = 50 #最大允许长度 self.previousHead = 0, 0 #先前的蛇的头部 self.randomFoodLocation() return imgMain game = SnakeGameClass("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] #第八个坐标点的 x, y值,其中 z 值不被包括在里面 #cv2.circle(img, pointIndex, 20, (200, 0, 200), cv2.FILLED) #在关键点处绘制一个圆点并进行填充(此处只是示范,后面会更改) img = game.update(img, pointIndex) cv2.imshow("Image", img) key = cv2.waitKey(1) #按下‘r'重新开始游戏 if key == ord('r'): game.gameOver = False
Quant aux besoins Le patron donut utilisé peut être remplacé par un patron de taille adaptée en ligne.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!