欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python利用手勢識別實現貪吃蛇游戲

 更新時間:2022年04月30日 09:22:28   作者:一馬歸一碼  
想必大家都玩過貪吃蛇的游戲吧:通過操縱蛇的移動方向能夠讓蛇吃到隨機出現的食物,吃到的食物越多,蛇就會變得越長。本文將使用手勢識別來完成貪吃蛇這個簡單的游戲,感興趣的可以了解一下

一、前言

想必大家都玩過貪吃蛇的游戲吧:通過操縱蛇的移動方向能夠讓蛇吃到隨機出現的食物,吃到的食物越多,蛇就會變得越長,但如果不小心撞到了自己,那么蛇就會死亡,game over!! 我們玩過的貪吃蛇游戲一般都是在手機或者游戲機上進行的,通過方向鍵操縱蛇的移動,那么我們是否可以直接使用一個攝像頭捕捉我們的手勢動作,并用手的移動來代表貪吃蛇的移動呢?當然可以,今天我就和大家一起完成這個游戲的設計并愉快的玩耍。

Let's Start!

二、項目介紹

1、游戲的操作方式

貪吃蛇游戲人盡皆知,計算機視覺鮮為人知,計算機視覺+貪吃蛇游戲會帶給人們更多的參與感以及新鮮度,本次這個項目就是主要使用手勢識別來完成貪吃蛇這個簡單的游戲。在這個游戲中,電腦通過攝像頭捕捉到我們的手勢并判別是否進行移動,玩家移動手去操縱貪吃蛇得到屏幕中隨機出現的食物,每得到一個食物,就會算作一分,Score 就會加1并顯示在畫面中,當玩家在操作的過程中不小心使得蛇的頭部和身體相撞,那么就會顯示GameOver! 按下 ‘r’ 鍵可以重新開始游戲。

2、開發(fā)的過程中的注意事項

(1) 圖像的左右問題

由于我們是使用手勢來進行控制蛇的移動的,但攝像頭的畫面顯示的是別人的視角,所以這和玩家的左右意識剛好是相反的,因此我們要將攝像頭讀取到的畫面進行一個左右的翻轉。原理上說就是將左右的像素點位置進行一個調換,但在 Python 中可以使用一個 cv2.flip( ) 函數就可以實現鏡像翻轉了。

(2) 攝像頭的畫面尺寸問題

過攝像頭得到的圖像我們需要在上面進行游戲,因此畫面過小會導致游戲空間不足,在最開始可以對畫面的大小進行一個預處理,設定一個較為合理的大小,最后得到的畫面玩游戲時才不會顯得局促。通過函數 cap.set(3, m) cap.set(4, n) 可以實現對畫面的寬和高的設定。

本項目中還會存在一些其他的注意事項,比如判斷碰撞,判斷獲得食物等,我會在后面的項目過程中再加以介紹。

三、游戲的實現要點

1、選擇第三方庫

一些使用到的第三方庫:

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

在本次項目中,我們主要使用到以上的幾個庫,其中使用 random 庫來隨機選擇像素點來放置食物甜甜圈,使用 cvzone 中的手部識別來進行玩家手勢的檢測,使用 cv2 來進行一些基礎的圖像操作,其他的一些庫也各有用處,后面一一介紹。

2、找到關鍵點并標記

在本次游戲中我們是選擇了一只手作為目標節(jié)點,所以當我們檢測到畫面中出現手部時需要對其中的關鍵點進行標記,而這個關鍵點恰好是我們的貪吃蛇的頭部,由于我們是調用的第三方庫,而該庫可以對手部進行3D的標記,但我們只需要 x,y 兩個坐標值就可以了,主要使用以下函數進行手部關鍵節(jié)點的標記:

#檢測到第一個手,并標記手部位置
    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、創(chuàng)建一個類來保存關于游戲的所有功能

我們需要實現的游戲是很多功能結合起來完成的,如果想要使用函數來實現這些功能,那么將會非常麻煩,當我們使用 class 來完成時,由于很多東西都保存在同一個類中,將會降低難度。在這個 class 中我們將會創(chuàng)建很多重要的列表來存儲我們用得到的一些關鍵點,比如貪吃蛇的身上的所有的點、貪吃蛇的長度、蛇的總體距離、食物的放置、得分等:

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、定義函數進行不斷更新 

隨著我們的手部的移動,貪吃蛇的長度以及位置都會發(fā)生變化,所以我們需要創(chuàng)建一個函數來不斷進行更新,滿足變化的需求(該部分也是在前面創(chuàng)建的大類里面完成的):

    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

在這個更新的函數中,我們需要判斷很多東西,比如貪吃蛇是否觸碰到食物(如果觸碰到食物我們就要增加蛇的長度并累積得分)、當前長度是否超過所允許的最大長度(當前長度小于最大長度就不必要進行更改了,但如果當前長度大于最大長度,則需要進行縮短)、貪吃蛇是否發(fā)生碰撞(通過關鍵節(jié)點之間的距離判斷貪吃蛇是否發(fā)生了碰撞,如果發(fā)生了碰撞,則進入 gameover 模塊,如果沒有,繼續(xù)游戲)等,都解釋在上面的代碼中了。

主要是通過上面定義的 class 我們就能實現當前的貪吃蛇游戲了。

四、總體代碼

本次小游戲我是在b站看到教程并一步步復現出來的,大家感興趣可以嘗試一下,當然按照慣例整體代碼會貼在下面:

"""
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

至于需要使用到的甜甜圈的圖案,可以網上找一個合適的大小的圖案進行替代即可。

到此這篇關于Python利用手勢識別實現貪吃蛇游戲的文章就介紹到這了,更多相關Python貪吃蛇游戲內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Python中規(guī)范定義命名空間的一些建議

    Python中規(guī)范定義命名空間的一些建議

    命名空間是Python程序的一大根本,編程時持命名空間的整潔還是十分必要的,這里就來為大家總結Python中規(guī)范定義命名空間的一些建議,需要的朋友可以參考下
    2016-06-06
  • Python中._pth文件的作用及說明

    Python中._pth文件的作用及說明

    這篇文章主要介紹了Python中._pth文件的作用及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • Pipenv輕量級虛擬環(huán)境管理工具使用指南

    Pipenv輕量級虛擬環(huán)境管理工具使用指南

    這篇文章主要為大家介紹了Pipenv輕量級虛擬環(huán)境管理工具使用指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • Python爬蟲進階之爬取某視頻并下載的實現

    Python爬蟲進階之爬取某視頻并下載的實現

    這篇文章主要介紹了Python爬蟲進階之爬取某視頻并下載的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • flask框架配置mysql數據庫操作詳解

    flask框架配置mysql數據庫操作詳解

    這篇文章主要介紹了flask框架配置mysql數據庫操作,結合實例形式詳細分析了flask框架配置mysql數據庫及連接訪問等相關操作技巧,需要的朋友可以參考下
    2019-11-11
  • python使用rstrip函數刪除字符串末位字符

    python使用rstrip函數刪除字符串末位字符

    rstrip函數用于刪除字符串末位指定字符,默認為空白符,這篇文章主要介紹了python使用rstrip函數刪除字符串末位字符的方法,需要的朋友可以參考下
    2023-04-04
  • Python實現序列化及csv文件讀取

    Python實現序列化及csv文件讀取

    這篇文章主要介紹了Python實現序列化及csv文件讀取,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-01-01
  • conda?install?nb_conda失敗原因分析及解決

    conda?install?nb_conda失敗原因分析及解決

    這篇文章主要給大家介紹了關于conda?install?nb_conda失敗原因分析及解決方法,conda install nb_conda顯示錯誤的原因可能有很多,具體原因取決于你的系統(tǒng)環(huán)境和安裝的conda版本,需要的朋友可以參考下
    2023-11-11
  • OpenCV根據面積篩選連通域學習示例

    OpenCV根據面積篩選連通域學習示例

    這篇文章主要為大家介紹了OpenCV根據面積篩選連通域學習示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • python實現上傳下載文件功能

    python實現上傳下載文件功能

    這篇文章主要為大家詳細介紹了python實現上傳下載文件功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07

最新評論