Cara Python menggunakan pengecaman gerak isyarat untuk melaksanakan permainan Snake

WBOY
Lepaskan: 2023-05-11 20:19:04
ke hadapan
1408 orang telah melayarinya

    Pengenalan Projek

    1 Cara mengendalikan permainan

    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.

    Cara Python menggunakan pengecaman gerak isyarat untuk melaksanakan permainan Snake

    2 Perkara yang perlu diambil perhatian semasa proses pembangunan

    (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.

    3. Titik pelaksanaan permainan

    1 Pilih perpustakaan pihak ketiga

    Sesetengah perpustakaan pihak ketiga yang digunakan:

    import math
    import random
    import cvzone
    import cv2
    import numpy as np
    from cvzone.HandTrackingModule import HandDetector
    Salin selepas log masuk

    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.

    2 Cari mata utama dan tandainya

    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) #在关键点处绘制一个圆点并进行填充(此处只是示范,后面会更改)
    Salin selepas log masuk

    3. Buat kelas untuk menyimpan semua fungsi tentang permainan

    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
    Salin selepas log masuk

    4 Tentukan fungsi untuk mengemas kini secara berterusan

    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&#39;Score: {self.score}&#39;, [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
    Salin selepas log masuk

    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.

    4. Kod keseluruhan

    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&#39;Your Score: {self.score}&#39;, [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&#39;Score: {self.score}&#39;, [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
    Salin selepas log masuk

    Untuk corak donut yang perlu anda gunakan, anda boleh mencari corak saiz yang sesuai untuk menggantikannya.

    Cara Python menggunakan pengecaman gerak isyarat untuk melaksanakan permainan Snake

    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!

    Label berkaitan:
    sumber:yisu.com
    Kenyataan Laman Web ini
    Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
    Tutorial Popular
    Lagi>
    Muat turun terkini
    Lagi>
    kesan web
    Kod sumber laman web
    Bahan laman web
    Templat hujung hadapan