Rumah > Artikel > pembangunan bahagian belakang > Cara Python menggunakan pengecaman gerak isyarat untuk melaksanakan permainan Snake
Semua orang tahu tentang permainan Snake, tetapi sedikit yang diketahui tentang penglihatan komputer. . Komputer visi + Permainan Ular akan membawa lebih banyak penyertaan dan kesegaran Projek ini terutamanya menggunakan pengecaman isyarat untuk melengkapkan permainan mudah Ular. Dalam permainan ini, komputer menangkap gerak isyarat kita melalui kamera dan menentukan sama ada pemain menggerakkan tangannya untuk mengawal ular untuk mendapatkan makanan yang muncul secara rawak pada skrin Setiap kali makanan diperoleh, ia akan dikira sebagai satu mata, dan Skor akan menjadi Tambah 1 dan memaparkannya pada skrin Apabila pemain secara tidak sengaja berlanggar dengan kepala dan badan ular semasa operasi, GameOver akan dipaparkan.
(1) Isu kiri dan kanan imej
Memandangkan kami menggunakan gerak isyarat untuk melakukannya Ia mengawal pergerakan ular, tetapi gambar kamera menunjukkan perspektif orang lain, jadi ini betul-betul bertentangan dengan kesedaran kiri dan kanan pemain, jadi kita perlu menyelak gambar yang dibaca oleh kamera ke kiri dan kanan. Pada dasarnya, kedudukan piksel kiri dan kanan ditukar, tetapi dalam Python anda boleh menggunakan fungsi cv2.flip() untuk mencapai cermin flipping.
(2) Masalah saiz skrin kamera
Kita perlu bermain permainan pada imej yang diperolehi oleh
melalui kamera, jadi skrin terlalu kecil, yang akan membawa kepada ruang permainan tidak mencukupi Pada mulanya, anda boleh Melakukan pra-pemprosesan pada saiz skrin dan menetapkan saiz yang lebih munasabah, supaya skrin akhir tidak akan kelihatan sempit semasa bermain permainan. Lebar dan ketinggian skrin boleh ditetapkan melalui fungsi cap.set(3, m) cap.set(4, n).
Ada juga beberapa perkara lain yang perlu diberi perhatian dalam projek ini, seperti menentukan perlanggaran, menentukan perolehan makanan, dll. Saya akan memperkenalkannya kemudian dalam proses projek.
Sesetengah perpustakaan pihak ketiga yang digunakan:
import math import random import cvzone import cv2 import numpy as np from cvzone.HandTrackingModule import HandDetector
Dalam projek ini, kami terutamanya gunakan perpustakaan di atas, antaranya kami menggunakan perpustakaan rawak untuk memilih piksel secara rawak untuk meletakkan donat makanan, menggunakan pengecaman tangan dalam cvzone untuk mengesan gerak isyarat pemain, dan menggunakan cv2 untuk melaksanakan beberapa operasi imej asas , beberapa perpustakaan lain juga mempunyai kegunaannya sendiri , yang akan diperkenalkan satu persatu nanti.
Dalam permainan ini kami memilih tangan sebagai nod sasaran, jadi apabila kami mengesan tangan muncul di skrin, kami perlu Menandai kekunci titik, dan titik utama ini menjadi ketua ular tamak kami Memandangkan kami memanggil perpustakaan pihak ketiga, perpustakaan boleh menandakan tangan dalam 3D, tetapi kami hanya memerlukan dua koordinat x dan y cukup, terutamanya gunakan fungsi berikut untuk menandakan nod utama tangan:
#检测到第一个手,并标记手部位置 if hands: lmList = hands[0]['lmList'] pointIndex = lmList[8][0:2] #第八个坐标点的 x, y值,其中 z 值不被包括在里面 cv2.circle(img, pointIndex, 20, (200, 0, 200), cv2.FILLED) #在关键点处绘制一个圆点并进行填充(此处只是示范,后面会更改)
Permainan yang perlu kita laksanakan mempunyai banyak fungsi Gabungan, jika anda ingin menggunakan fungsi untuk melaksanakan fungsi ini, ia akan menjadi sangat menyusahkan Apabila kita menggunakan kelas untuk menyelesaikannya, kerana banyak perkara yang disimpan dalam kelas yang sama, kesukaran akan dikurangkan. Dalam kelas ini, kami akan membuat banyak senarai penting untuk menyimpan beberapa perkara penting yang kami gunakan, seperti semua titik pada badan ular, panjang ular, jarak keseluruhan ular, penempatan makanan, markah, dll. :
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
Apabila tangan kita bergerak, panjang dan kedudukan ular akan berubah, jadi kita perlu mencipta fungsi untuk mengemas kini Kemas kini secara berterusan untuk memenuhi keperluan yang berubah. (bahagian ini juga dilengkapkan dalam kategori besar yang dibuat sebelum ini):
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
Dalam fungsi yang dikemas kini ini, kita perlu menentukan banyak perkara, seperti sama ada ular yang tamak itu menyentuh makanan (Jika kita menyentuh makanan, kita akan meningkatkan panjang ular dan mengumpul mata), sama ada panjang semasa melebihi panjang maksimum yang dibenarkan (jika panjang semasa kurang daripada panjang maksimum, tidak perlu mengubahnya, tetapi jika panjang semasa lebih besar daripada panjang maksimum, perlu memendekkan), sama ada ular itu berlanggar (tentukan sama ada ular berlanggar dengan jarak antara nod utama, jika perlanggaran berlaku, masukkan modul gameover, jika tidak, teruskan permainan), dll., semuanya dijelaskan di atas Kod rosak.
Terutamanya melalui kelas yang ditakrifkan di atas, kita boleh merealisasikan permainan ular semasa.
Saya melihat tutorial di stesen b dan mengeluarkannya semula langkah demi langkah untuk permainan mini ini Jika anda berminat, sudah tentu, kod keseluruhannya akan dipos seperti biasa di bawah:
""" 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
Untuk corak donut yang perlu anda gunakan, anda boleh mencari corak saiz yang sesuai untuk menggantikannya.
Atas ialah kandungan terperinci Cara Python menggunakan pengecaman gerak isyarat untuk melaksanakan permainan Snake. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!