首頁/ 遊戲/ 正文

一小時學會用 Opencv 做貪吃蛇遊戲(Python版)

作者 | 原始碼•宸

使用Mediapipe

一小時學會用 Opencv 做貪吃蛇遊戲(Python版)

水平映象處理

import

cvzone

import

cv2

import

numpy

as

np

from

cvzone。HandTrackingModule

import

HandDetector

cap = cv2。VideoCapture(

0

# 0代表自己電腦的攝像頭

cap。set(

3

1280

# 寬

cap。set(

4

720

# 高

detector = HandDetector(detectionCon=

0。8

, maxHands=

2

# 處理每一幀影象

while

True

success, img = cap。read()

# 翻轉影象,使自身和攝像頭中的自己呈映象關係

img = cv2。flip(img,

1

# 將手水平翻轉

hands, img = detector。findHands(img)

cv2。imshow(

“Image”

, img)

cv2。waitKey(

1

一小時學會用 Opencv 做貪吃蛇遊戲(Python版)

修改程式碼

import

cvzone

import

cv2

import

numpy

as

np

from

cvzone。HandTrackingModule

import

HandDetector

cap = cv2。VideoCapture(

0

# 0代表自己電腦的攝像頭

cap。set(

3

1280

# 寬

cap。set(

4

720

# 高

detector = HandDetector(detectionCon=

0。8

, maxHands=

1

# 處理每一幀影象

while

True

success, img = cap。read()

# 翻轉影象,使自身和攝像頭中的自己呈映象關係

img = cv2。flip(img,

1

# 將手水平翻轉

hands, img = detector。findHands(img, flipType=

False

# 左手是左手,右手是右手,對映正確

cv2。imshow(

“Image”

, img)

cv2。waitKey(

1

問題修復完畢

一小時學會用 Opencv 做貪吃蛇遊戲(Python版)

觀察手的資訊

import

cvzone

import

cv2

import

numpy

as

np

from

cvzone。HandTrackingModule

import

HandDetector

cap = cv2。VideoCapture(

0

# 0代表自己電腦的攝像頭

cap。set(

3

1280

# 寬

cap。set(

4

720

# 高

detector = HandDetector(detectionCon=

0。8

, maxHands=

1

# 處理每一幀影象

while

True

success, img = cap。read()

# 翻轉影象,使自身和攝像頭中的自己呈映象關係

img = cv2。flip(img,

1

# 將手水平翻轉

hands, img = detector。findHands(img, flipType=

False

# 左手是左手,右手是右手,對映正確

print(hands)

cv2。imshow(

“Image”

, img)

cv2。waitKey(

1

輸出結果

[{‘lmList’: [[1088, 633, 0], [1012, 655, -24], [940, 629, -32], [894, 596, -35], [875, 562, -36], [949, 504, -17], [891, 441, -16], [862, 419, -16], [838, 403, -16], [995, 480, -3], [943, 418, 8], [924, 426, 17], [920, 440, 22], [1044, 480, 8], [998, 455, 17], [987, 489, 21], [993, 513, 23], [1085, 492, 19], [1048, 477, 27], [1036, 505, 35], [1041, 528, 40]], ‘bbox’: (838, 403, 250, 252), ‘center’: (963, 529), ‘type’: ‘Left’}]

做個小蛇

import math

import cvzone

import cv2

import numpy as np

from cvzone。HandTrackingModule import HandDetector

cap = cv2。VideoCapture(

0

# 0代表自己電腦的攝像頭

cap。set(

3

1280

# 寬

cap。set(

4

720

# 高

detector = HandDetector(detectionCon=

0

8

, maxHands=

1

class

SnakeGameClass

def

__init__

self

# 構造方法

self

。points = []

# 蛇身上所有的點

self

。lengths = []

# 每個點之間的長度

self

。currentLength =

0

# 蛇的總長

self

。allowedLength =

150

# 蛇允許的總長度

self

。previousHead =

0

0

# 第二個頭結點

def

update

self

, imgMain, currentHead)

# 例項方法

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

# Draw Snake

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

, (

200

0

200

), cv2。FILLED)

return

imgMain

game = SnakeGameClass()

# 處理每一幀影象

while

True:

# 不斷迭代更新

success, img = cap。read()

# 翻轉影象,使自身和攝像頭中的自己呈映象關係

img = cv2。flip(img,

1

# 將手水平翻轉

hands, img = detector。findHands(img, flipType=False)

# 左手是左手,右手是右手,對映正確

if

hands:

lmList = hands[

0

][

‘lmList’

# hands是由N個字典組成的列表

pointIndex = lmList[

8

][

0

2

# 只要食指指尖的x和y座標

img = game。update(img, pointIndex)

cv2。imshow(

“Image”

, img)

cv2。waitKey(

1

新增甜甜圈

import

math

import

random

import

cvzone

import

cv2

import

numpy

as

np

from

cvzone。HandTrackingModule

import

HandDetector

cap = cv2。VideoCapture(

0

# 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 =

150

# 蛇允許的總長度

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

def

randomFoodLocation

(self)

self。foodPoint = random。randint(

100

1000

), random。randint(

100

600

def

update

(self, imgMain, currentHead)

# 例項方法

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

break

# 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

, (

200

0

200

), cv2。FILLED)

# Draw Food

rx, ry = self。foodPoint

imgMain = cvzone。overlayPNG(imgMain, self。imgFood,

(rx - self。wFood //

2

, ry - self。hFood //

2

))

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’

# hands是由N個字典組成的列表

pointIndex = lmList[

8

][

0

2

# 只要食指指尖的x和y座標

img = game。update(img, pointIndex)

cv2。imshow(

“Image”

, img)

cv2。waitKey(

1

donut。png

部分程式碼解釋說明

imgMain = cvzone。overlayPNG(imgMain,

self

。imgFood,                                    (rx -

self

。wFood

// 2, ry - self。hFood // 2))

為什麼不是

imgMain

= cvzone。overlayPNG(imgMain, self。imgFood, (rx , ry))

那是因為,隨機生成一個點後,有座標(x,y)

一小時學會用 Opencv 做貪吃蛇遊戲(Python版)

增加分數機制

import

math

import

random

import

cvzone

import

cv2

import

numpy

as

np

from

cvzone。HandTrackingModule

import

HandDetector

cap = cv2。VideoCapture(

0

# 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 =

150

# 蛇允許的總長度

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

def

randomFoodLocation

(self)

self。foodPoint = random。randint(

100

1000

), random。randint(

100

600

def

update

(self, imgMain, currentHead)

# 例項方法

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

break

# Check if snake ate the food

rx, ry = self。foodPoint

if

rx - self。wFood //

2

2

and

\

ry - self。hFood //

2

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

, (

200

0

200

), cv2。FILLED)

# Draw Food

imgMain = cvzone。overlayPNG(imgMain, self。imgFood,

(rx - self。wFood //

2

, ry - self。hFood //

2

))

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’

# hands是由N個字典組成的列表

pointIndex = lmList[

8

][

0

2

# 只要食指指尖的x和y座標

img = game。update(img, pointIndex)

cv2。imshow(

“Image”

, img)

cv2。waitKey(

1

完整程式碼

import

math

import

random

import

cvzone

import

cv2

import

numpy

as

np

from

cvzone。HandTrackingModule

import

HandDetector

cap = cv2。VideoCapture(

0

# 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 =

150

# 蛇允許的總長度

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

# 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

break

# Check if snake ate the food

rx, ry = self。foodPoint

if

rx - self。wFood //

2

2

and

\

ry - self。hFood //

2

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

, (

200

0

200

), cv2。FILLED)

# Draw Food

imgMain = cvzone。overlayPNG(imgMain, self。imgFood,

(rx - self。wFood //

2

, ry - self。hFood //

2

))

cvzone。putTextRect(imgMain,

f‘Your Score:

{self。score}

, [

50

80

],

scale=

3

, thickness=

5

, offset=

10

# Check for Collision

pts = np。array(self。points[:

-2

], np。int32)

pts = pts。reshape((

-1

1

2

))

# 重塑為一個行數未知但只有一列且每個元素有2個子元素的矩陣

cv2。polylines(imgMain, [pts],

False

, (

0

200

0

),

3

# 第三個引數是False,我們得到的是不閉合的線

minDist = cv2。pointPolygonTest(pts, (cx, cy),

True

# 引數True表示輸出該畫素點到輪廓最近距離

if

-1

1:

print(

“Hit”

self。gameOver =

True

self。points = []

# 蛇身上所有的點

self。lengths = []

# 每個點之間的長度

self。currentLength =

0

# 蛇的總長

self。allowedLength =

150

# 蛇允許的總長度

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’

# hands是由N個字典組成的列表

pointIndex = lmList[

8

][

0

2

# 只要食指指尖的x和y座標

img = game。update(img, pointIndex)

cv2。imshow(

“Image”

, img)

key = cv2。waitKey(

1

if

key == ord(

‘r’

):

game。gameOver =

False

開啟App看更多精彩內容

相關文章

頂部