使用Opencv和Python構建貪吃蛇小游戲
點擊上方“AI算法與圖像處理”,選擇加"星標"或“置頂”
重磅干貨,第一時間送達
導讀
?本文詳細介紹貪吃蛇小游戲,主要是使用方向鍵來控制小蛇的移動,并讓小蛇盡可能多的吃到地圖中的小蘋果,變得更長。
基礎工作
導入基礎程序庫
首先需要導入我們所需要的各種程序庫。
import cv2import numpy as npform random import randintform?random?import?choice
定義小蛇的基礎構成
在這個程序中,我們的小蛇由頭部和身體組成。
頭部:使用Head類來表示蛇頭,即蛇頭是整條蛇的最開始部分。
身體:對于一條小蛇,除了蛇頭外,都是身體。
具體如下圖所示。

接下來,我們分別定義小蛇的頭部類和身體類。
頭部類
因為整個小蛇是二維平面的小蛇,因此,確定一個蛇頭的位置需要x和y兩個值。此外,對于蛇頭的移動方向,需要一個direction變量來確定。具體代碼如下。
class Head:def __init__(self, direction, x, y):# 蛇頭運動的方向self.direction = direction# 蛇頭在二維平面的坐標self.x = xself.y = y# 移動函數(shù),通過不同的方向來對蛇頭的位置進行更新def move(self):# 右if self.direction == 0:self.x += 1# 下elif self.direction == 1:self.y += 1# 左elif self.direction == 2:self.x -= 1# 上elif self.direction == 3:self.y -= 1
身體類
身體類也需要使用x和y來確定位置,但由于每個身體但小塊的運動均依賴于前一個小塊的運動,因此,身體類沒有direction變量,有的只是front變量,用來讓身體知道自己的上一塊的位置。具體代碼如下。
class SnakePart:def __init__(self, front, x, y):self.front = frontself.x = xself.y = y# 移動函數(shù),當前小塊的下一個位置為當前小塊的前一個小塊的當前位置def move(self):self.x = self.front.x????self.y?=?self.front.y
定義游戲變量
CELL_SIZE:每個單元格的寬度。
BOARD_SIZE:每一行有多少個單元格。
SPEED:小蛇運動的速度。
GROWTH:小蛇每吃掉一個蘋果后,蘋果出現(xiàn)的速度。
等等。。。
# 每個單元格的寬度CELL_SIZE = 20# 每一行有多少個單元格BOARD_SIZE = 45# 小蛇運動的速度。SPEED = 12# 小蛇每吃掉一個蘋果后,小蛇增長的速度。GROWTH = 3# 判斷蘋果是否被吃了eaten = True# 判斷是否推出游戲quit = False# 變量增長.grow = 0# 使用數(shù)組來儲存小蛇snake = []# 初始化小蛇的頭部并放在中間head = Head(0, int((BOARD_SIZE - 1)/2), int((BOARD_SIZE - 1)/2))??snake.append(head)
編寫游戲
初始化opencv窗口
除了初始化窗口外,這個函數(shù)還可以讓用戶的焦點自動到該貪吃蛇游戲中。
# 構建窗口并獲取焦點def win_focus():cv2.namedWindow("Snake Game", cv2.WINDOW_AUTOSIZE);board = np.zeros([BOARD_SIZE * CELL_SIZE, BOARD_SIZE * CELL_SIZE, 3])cv2.imshow("Snake Game", board);cv2.setWindowProperty("Snake Game", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN);cv2.waitKey(2000)??cv2.setWindowProperty("Snake?Game",?cv2.WND_PROP_FULLSCREEN,?cv2.WINDOW_AUTOSIZE)
展現(xiàn)游戲
這個函數(shù)需要完成的功能如下。
創(chuàng)建一個用于給小蛇活動的黑色背景板。
把蛇的身體(包括頭部)設置為綠色。
把蘋果設置成紅色。
監(jiān)聽鍵盤按鍵信息。
具體代碼如下。
def display():# 創(chuàng)建黑色背景板board = np.zeros([BOARD_SIZE, BOARD_SIZE, 3])# 讓小蛇變成綠色for part in snake:board[part.y, part.x] = [0, 255, 0]# 讓蘋果變成紅色board[appley, applex] = [0, 0, 255]# 顯示背景板,刷新,返回鍵盤按鍵信息cv2.imshow("Snake Game", np.uint8(board.repeat(CELL_SIZE, 0).repeat(CELL_SIZE, 1)))key = cv2.waitKey(int(1000/SPEED))# 沒有任何按鍵被按下時返回-1??return?key
游戲主循環(huán)
在游戲主循環(huán)中,主要完成兩件事
檢查地圖中的蘋果是否被吃了。
如果被吃,需要增長小蛇長度,并重新生成一個新的不被小蛇覆蓋的蘋果。
# 判斷蘋果是否被吃if eaten:# 將二維地圖轉(zhuǎn)換為一維序列s = list(range(0, BOARD_SIZE ** 2))# 將序列中被小蛇占有的值給剔除for part in snake:s.remove(part.x * BOARD_SIZE + part.y)# 隨機生成一個不被小蛇覆蓋的新蘋果a = choice(s)applex = int(a/BOARD_SIZE)appley = a % BOARD_SIZE??eaten?=?False
刷新屏幕并更新移動方向
# 刷新屏幕key = display()# 根據(jù)按鍵的信息來控制小蛇的運動方向if key == 8 or key == 27:breakelif key == ord("d") :head.direction = 0elif key == ord("s") :head.direction = 1elif key == ord("a") :head.direction = 2elif key == ord("w") :head.direction = 3# 移動小蛇# 從后往前移動,因為后一個小塊使用的是前一個小塊的位置for part in snake[::-1]:part.move()
小蛇吃到蘋果后長大
# 當小蛇吃到蘋果后的生長代碼if grow > 0:# 在蛇身的后尾添加上新的蛇身塊snake.append(SnakePart(snake[-1], subx, suby))grow -= 1# 當蛇頭碰到蘋果,更新變量if applex == head.x and appley == head.y:subx = snake[-1].xsuby = snake[-1].yeaten = True??grow?+=?GROWTH
游戲失敗的判斷
# 碰撞墻壁規(guī)則if head.x < 0 or head.x > BOARD_SIZE - 1 or head.y < 0 or head.y > BOARD_SIZE - 1:break# 蛇頭碰撞蛇身規(guī)則for part in snake[1:]:if head.x == part.x and head.y == part.y:quit = Truebreakif quit:??break
小結
這只是一個小的Demo,大家感興趣可以去下載源代碼,并讓這個游戲變得更加的具有可玩性。
代碼:https://github.com/spmallick/learnopencv/tree/master/SnakeGame
英文原文:https://learnopencv.com/snake-game-with-opencv-python/
個人微信(如果沒有備注不拉群!) 請注明:地區(qū)+學校/企業(yè)+研究方向+昵稱
下載1:何愷明頂會分享
在「AI算法與圖像處理」公眾號后臺回復:何愷明,即可下載。總共有6份PDF,涉及 ResNet、Mask RCNN等經(jīng)典工作的總結分析
下載2:終身受益的編程指南:Google編程風格指南
在「AI算法與圖像處理」公眾號后臺回復:c++,即可下載。歷經(jīng)十年考驗,最權威的編程規(guī)范!
下載3 CVPR2020 在「AI算法與圖像處理」公眾號后臺回復:CVPR2020,即可下載1467篇CVPR?2020論文
覺得不錯就點亮在看吧

