在很久很久以前,手機(jī)屏幕都還是黑白的年代,有一款叫做“貪吃蛇”的游戲風(fēng)靡了大街小巷,在那分辨率極低的屏幕上,幾條扭扭曲曲的弧線似乎穿越了整個(gè)童年。
這節(jié)課上,就讓我們用DFRobot行空板來(lái)實(shí)現(xiàn)一下這款經(jīng)典的游戲吧!
任務(wù)目標(biāo)
在屏幕上進(jìn)行貪吃蛇小游戲。


知識(shí)點(diǎn)
1、認(rèn)識(shí)pygame庫(kù)
2、學(xué)習(xí)使用pygame庫(kù)創(chuàng)建游戲窗口的方法
3、學(xué)習(xí)使用pygame庫(kù)繪制圖形、繪制文本、更新屏幕顯示的方法
4、學(xué)習(xí)使用pygame庫(kù)實(shí)現(xiàn)鍵盤(pán)交互的方法
材料清單
硬件清單:


軟件使用:Mind+編程軟件x1
知識(shí)儲(chǔ)備
1、貪吃蛇小游戲?qū)崿F(xiàn)原理與邏輯
(1)實(shí)現(xiàn)原理
在這個(gè)貪吃蛇游戲中,我們將整個(gè)游戲區(qū)域劃分成一個(gè)個(gè)的小格子,每一個(gè)格子的所在位置可以通過(guò)行列來(lái)表示,由一組連在一起的小格子組成“蛇”,“蛇”分為“蛇頭”和“蛇身”兩部分。“蛇頭”用一個(gè)格子表示,“蛇身”用一個(gè)列表來(lái)存儲(chǔ),結(jié)合不同的顏色,這樣一條“蛇”就出來(lái)了。“蛇”的移動(dòng)則是將下一格的行列位置添加到列表開(kāi)頭,并移除列表的最后一個(gè)元素,就相當(dāng)于“蛇”向前移動(dòng)了一格。食物同樣以格子的形式隨機(jī)呈現(xiàn),當(dāng)“蛇頭”與食物的位置重合,那么“蛇”就吃到了食物,而當(dāng)“蛇”移動(dòng)超出了范圍亦或者“蛇頭”撞在了“蛇身”上,那么游戲結(jié)束并計(jì)算食物數(shù)量。
(2)游戲邏輯圖
由于游戲包含了蛇的移動(dòng)、吃食物、事件監(jiān)測(cè)、結(jié)束游戲等多個(gè)功能,在編程時(shí),我們可以通過(guò)定義函數(shù)的方式,實(shí)現(xiàn)各個(gè)不同的功能部分,之后依據(jù)游戲邏輯在所需處調(diào)用即可。

2、什么是pygame庫(kù)
pygame是專(zhuān)為電子游戲設(shè)計(jì)的跨平臺(tái)Python庫(kù)。通過(guò)它,我們可以設(shè)計(jì)包含圖像、聲音等元素的電子游戲。pygame做游戲開(kāi)發(fā)的優(yōu)勢(shì)在于不需要過(guò)多地考慮底層相關(guān)的內(nèi)容,而可以把重心放在游戲邏輯上,例如,pygame中集成了很多和底層相關(guān)的模塊,如訪問(wèn)顯示設(shè)備、管理事件、使用字體等。關(guān)于pygame常用的一些模塊可參考下表。
模塊名 | 功能 |
pygame.display | 訪問(wèn)顯示設(shè)備 |
pygame.event | 管理事件 |
pygame.draw | 繪制形狀、線和點(diǎn) |
pygame.key | 讀取鍵盤(pán)按鍵 |
pygame.mouse | 控制鼠標(biāo)事件 |
pygame.music | 播放音頻 |
3、pygame庫(kù)常見(jiàn)函數(shù)
pygame庫(kù)中的函數(shù)有很多,我們只使用其中的一部分,編程時(shí),通過(guò)“import pygame”導(dǎo)入庫(kù)后可采用“pygame.函數(shù)名()”的形式來(lái)實(shí)現(xiàn)功能。
(1)init()函數(shù)初始化pygame模塊
通過(guò)init()函數(shù)我們可對(duì)pygame中的模塊進(jìn)行初始化,在編程時(shí),我們需要將這條指令放在其他pygame指令之前,初始化后方可使用其中的模塊。
pygame.init() # 初始化pygame
(2)quit()函數(shù)退出pygame庫(kù)
quit()函數(shù)是與init()函數(shù)功能相反的一個(gè)函數(shù),可以實(shí)現(xiàn)退出pygame,使pygame庫(kù)結(jié)束工作。在編程時(shí),我們通常在需要結(jié)束游戲時(shí)使用。
pygame.quit() # 退出pygame
4、pygame庫(kù)display模塊中的常用方法
pygame庫(kù)display模塊可用來(lái)訪問(wèn)顯示設(shè)備,以便在設(shè)備上顯示內(nèi)容。其中的方法有很多,我們只使用其中的一部分,在編程時(shí),可通過(guò)“模塊名.方法名()”的形式來(lái)實(shí)現(xiàn)功能。
(1)set_mode()方法初始化一個(gè)準(zhǔn)備顯示的窗口界面
set_mode()方法可以實(shí)現(xiàn)游戲窗口的創(chuàng)建
size=(240,320) # 定義尺寸
window = pygame.display.set_mode(size) # 創(chuàng)建游戲窗口,尺寸為(240,320)
其中,size是我們?cè)O(shè)定的要顯示的游戲窗口的尺寸大小,和行空板屏幕相同,window是一個(gè)生成的屏幕Surface對(duì)象,我們可以對(duì)它進(jìn)行填充顏色、涂畫(huà)、添加其他對(duì)象等各種操作。
如下,在填充顏色時(shí),我們可通過(guò)“對(duì)象.fill()”的指令實(shí)現(xiàn)。
bg_color=(255,255,255) # 定義背景色為白
window.fill(bg_color) # fillcolor # 填充窗口的背景顏色
而要想將其他對(duì)象添加到窗口對(duì)象上,我們可通過(guò)“對(duì)象.blit()”指令來(lái)實(shí)現(xiàn)。
window.blit(score, (40,250)) # 在窗口上(40,250)處顯示得分
(2)flip()方法更新屏幕
flip()方法可以將待顯示的畫(huà)面更新到屏幕上。通常,我們?cè)谑褂胮ygame.display模塊編寫(xiě)一些功能后,需要使用flip方法,才能將其更新顯示到屏幕上。
pygame.display.flip() # Refresh all displays to the window # 更新所有待顯示的內(nèi)容到屏幕
5、pygame庫(kù)draw模塊中的常用方法
pygame庫(kù)display模塊可用來(lái)繪制各種不同的形狀,其中的方法有很多,編程時(shí),可通過(guò)“模塊名.方法名()”的形式來(lái)實(shí)現(xiàn)功能。
(1)rect()方法繪制矩形
rect()方法可以實(shí)現(xiàn)矩形的繪制。
left=point.col*15 # 定義小方格距離左邊緣的距離
top=point.row*15 # 定義小方格距離上邊緣的距離
pygame.draw.rect(window,color,(left,top,15,15)) # 在窗口上繪制矩形,顏色為color
其中,window表示矩形繪制在窗口上,color是指矩形的顏色,left和top分別指矩形距離窗口左邊緣和上邊緣的距離,用以表示矩形的位置區(qū)域。
6、pygame庫(kù)font模塊中的常用方法
pygame庫(kù)font模塊可實(shí)現(xiàn)字體的使用,其中的方法有很多,編程時(shí),可通過(guò)“模塊名.方法名()”的形式來(lái)實(shí)現(xiàn)功能。
(1)SysFont()方法創(chuàng)建字體對(duì)象
SysFont()方法可以實(shí)現(xiàn)字體對(duì)象的創(chuàng)建。
font = pygame.font.SysFont('Arial', 20) # 設(shè)置字體
其中,Arial指的是具體的字體類(lèi)型,20指的是字體大小,font是一個(gè)變量用于存儲(chǔ)生成的字體對(duì)象。
而在創(chuàng)建好字體對(duì)象后,我們就可以在其上繪制具體的文本,以達(dá)到顯示的效果,我們可通過(guò)“對(duì)象.render()”指令來(lái)實(shí)現(xiàn)。
score = font.render('Your Score is ' , False, 'pink') # 計(jì)算得分
其中,'Your Score is '指的是具體繪制的文本,F(xiàn)alse表示無(wú)需抗鋸齒,pink指的是文本的顏色,score是一個(gè)變量用于存儲(chǔ)生成的文本。
7、pygame庫(kù)中的事件、事件類(lèi)型、鍵盤(pán)事件以及事件檢測(cè)
事件(Event)是 pygame 的重要模塊之一,它是構(gòu)建整個(gè)游戲程序的核心,比如鼠標(biāo)點(diǎn)擊、鍵盤(pán)敲擊、游戲窗口移動(dòng)、退出游戲等等,這些都可以看做是“事件”,pygame 會(huì)接受用戶(hù)產(chǎn)生的各種操作(或事件),這些操作隨時(shí)產(chǎn)生,并且操作量可大可小,那么 pygame 是如何處理這些事件的呢?
pygame 定義了一個(gè)專(zhuān)門(mén)用來(lái)處理事件的結(jié)構(gòu),即事件隊(duì)列,該結(jié)構(gòu)遵循隊(duì)列“先到先處理”的基本原則,通過(guò)事件隊(duì)列,我們可以有序的、逐一的處理用戶(hù)的操作(觸發(fā)事件)。對(duì)于 pygame 中常用的游戲事件,可參考下表:
事件類(lèi)型 | 描述 | 成員屬性 |
QUIT | 用戶(hù)按下窗口的關(guān)閉按鈕 | None |
KEYDOWN | 鍵盤(pán)按下 | unicode、key、mod |
KEYUP | 鍵盤(pán)放開(kāi) | key、mod |
MOUSEBUTTONDOWN | 鼠標(biāo)按下 | pos, button |
MOUSEBUTTONUP | 鼠標(biāo)放開(kāi) | pos, button |
Tips:當(dāng)使用 pygame 做游戲開(kāi)發(fā)時(shí),上述事件并非都會(huì)應(yīng)用的到。
其中,鍵盤(pán)事件會(huì)涉及到大量的按鍵操作,比如游戲中的上下左右,或者人物的前進(jìn)、后退等操作,這些都需要鍵盤(pán)來(lái)配合實(shí)現(xiàn)。
鍵盤(pán)事件提供了一個(gè) key 屬性,通過(guò)該屬性可以獲取鍵盤(pán)的按鍵。pygame 將鍵盤(pán)上的字母鍵、數(shù)字鍵、組合鍵等按鍵以常量的方式進(jìn)行了定義,對(duì)于部分常用按鍵的常量,可參考下表:
常量名 | 描述 |
K_SPACE | 空格鍵(Space) |
K_RETURN | 回車(chē)鍵(Enter) |
K_0...K_9 | 0...9 |
K_a...Kz | a...z |
K_UP | 向上箭頭(up arrow) |
K_DOWN | 向下箭頭(down arrow) |
K_LEFT | 向左箭頭(left arrow) |
K_RIGHT | 向右箭頭(right arrow) |
Tips :由于行空板在開(kāi)發(fā)時(shí)已做處理,將按鍵a、b映射為鍵盤(pán)上的a、b按鍵,因此,在獲取鍵盤(pán)事件時(shí),按下行空板上的按鍵a、b,同樣能夠被檢測(cè)出來(lái)。
最后,要想實(shí)現(xiàn)鍵盤(pán)按鍵控制游戲的進(jìn)行,那么我們就需要先檢測(cè)事件,那如何才能實(shí)現(xiàn)呢?
pygame庫(kù)event 模塊提供了處理事件隊(duì)列的常用方法,我們通過(guò)其中的get()方法就可以實(shí)現(xiàn)對(duì)于事件的檢測(cè)。
events = pygame.event.get() # 獲取事件
其中,events是一個(gè)變量,用來(lái)存儲(chǔ)檢測(cè)到的事件。
而在獲取到了事件之后,我們就可以對(duì)它進(jìn)行判別了
if (event.type == pygame.QUIT): # 如果事件類(lèi)型為退出(關(guān)閉窗口)
pygame.quit() # 退出游戲
if (event.type == pygame.KEYDOWN): # 如果事件類(lèi)型為鍵盤(pán)按下
if (event.key == pygame.K_a): # 如果是按鍵a被按下
.......
elif (event.key == pygame.K_b): # 如果是按鍵b被按下
其中,event.type表示事件的類(lèi)型,pygame.QUIT表示退出事件,pygame.KEYDOWN表示鍵盤(pán)按下事件,event.key表示鍵盤(pán)的按鍵, pygame.K_a表示按鍵a,pygame.K_b表示按鍵b。
動(dòng)手實(shí)踐
任務(wù)描述1:創(chuàng)建游戲窗口
通過(guò)pygame庫(kù)創(chuàng)建一個(gè)游戲窗口界面。
1、硬件搭建
通過(guò)USB連接線將行空板連接到計(jì)算機(jī)
2、程序編寫(xiě)
STEP1:創(chuàng)建與保存項(xiàng)目文件
啟動(dòng)Mind+,另存項(xiàng)目并命名為“006、貪吃蛇小游戲”。
STEP2:創(chuàng)建與保存Python文件
創(chuàng)建一個(gè)Python程序文件“main1.py”,雙擊打開(kāi)。
STEP3:程序編寫(xiě)
(1) 導(dǎo)入所需功能庫(kù)
在這個(gè)任務(wù)中,我們需要結(jié)合pygame庫(kù)和time庫(kù)來(lái)繪制游戲窗口,因此,我們須先導(dǎo)入它們。
import pygame # 導(dǎo)入pygame庫(kù)import time # 導(dǎo)入time庫(kù) |
(2) 初始化游戲并創(chuàng)建指定尺寸的游戲窗口
在使用pygame進(jìn)行游戲時(shí),我們需先對(duì)其進(jìn)行初始化操作,之后,為了能和行空板的屏幕一致,我們創(chuàng)建一個(gè)大小為(240,320)的游戲窗口。
pygame.init() # 游戲初始化W=240 # 定義寬H=320 # 定義高size=(240,320) # 定義尺寸window = pygame.display.set_mode(size) # 創(chuàng)建游戲窗口,尺寸為(240,320) |
(3) 定義背景色和初始運(yùn)行狀態(tài)
創(chuàng)建好游戲窗口后,我們?cè)贋槠涠x一個(gè)背景色和初始的運(yùn)行狀態(tài)以便在后續(xù)進(jìn)行設(shè)置。
bg_color=(255,255,255) # 定義背景色為白run=True # 定義初始運(yùn)行狀態(tài)為T(mén)rue,表示運(yùn)行 |
(4) 填充窗口的背景顏色并保持窗口顯示
接下來(lái),我們對(duì)窗口的背景進(jìn)行顏色的填充,而為了能使窗口始終保持顯示,我們需要不斷刷新窗口屏幕的顯示內(nèi)容,這里我們結(jié)合循環(huán)來(lái)實(shí)現(xiàn)。
while run: # 游戲循環(huán) window.fill(bg_color) # fillcolor # 填充窗口的背景顏色 pygame.display.flip() # Refresh all displays to the window # 更新所有待顯示的內(nèi)容到屏幕 time.sleep(0.2) # delay 0.2 seconds |
Tips:完整示例程序如下:
'''創(chuàng)建游戲窗口'''import pygame # 導(dǎo)入pygame庫(kù)import time # 導(dǎo)入time庫(kù) pygame.init() # 游戲初始化W=240 # 定義寬H=320 # 定義高size=(240,320) # 定義尺寸window = pygame.display.set_mode(size) # 創(chuàng)建游戲窗口,尺寸為(240,320)bg_color=(255,255,255) # 定義背景色為白run=True # 定義初始運(yùn)行狀態(tài)為T(mén)rue,表示運(yùn)行 while run: # 游戲循環(huán) window.fill(bg_color) # fillcolor # 填充窗口的背景顏色 pygame.display.flip() # Refresh all displays to the window # 更新所有待顯示的內(nèi)容到屏幕 time.sleep(0.2) # delay 0.2 seconds |
3、程序運(yùn)行
STEP1:遠(yuǎn)程連接行空板
STEP2:點(diǎn)擊右上方的運(yùn)行按鈕
STEP3:觀察效果
觀察行空板,首先可以看到行空板的屏幕變成了白色,而這,正是我們所創(chuàng)建游戲窗口的背景。

任務(wù)描述2:添加游戲元素
上述生成的屏幕窗口上空空如也,為了完善游戲,接下來(lái),我們將在其上添加游戲中的最重要的角色元素---蛇和食物。
1、程序編寫(xiě)
STEP1:創(chuàng)建與保存項(xiàng)目文件
新建一個(gè)Python程序文件“main2.py”,雙擊打開(kāi)。
Step2:程序編寫(xiě)
和任務(wù)一相同,在程序的開(kāi)始部分,我們依舊導(dǎo)入所需功能庫(kù),初始化游戲并創(chuàng)建游戲窗口。之后再在此基礎(chǔ)上編寫(xiě)其他部分程序。
(1)定義游戲方式
在貪吃蛇游戲中,有蛇和食物兩個(gè)最重要的元素,那么如何才能在我們的屏幕上表示它呢?
這里,我們將游戲窗口劃分成一個(gè)個(gè)小方格,通過(guò)方格來(lái)表示界面內(nèi)的元素,每個(gè)小方格的寬和高皆為15像素,這樣,由于窗口大小為240*320,因此在橫向上會(huì)有18個(gè)方格,縱向上會(huì)有24個(gè),即24行18列的小方格。
# 將游戲窗口劃分為一個(gè)個(gè)小方格,每個(gè)方格的寬和高皆為15,共計(jì)24行,18列ROW=24 # 定義行數(shù),每格15*15,24行18列COL=18 # 定義列數(shù)cell_width=W/COL # 定義格子的寬cell_height=H/ROW # 定義格子的高 |
(4)定義方格位置
接下來(lái),我們定義一個(gè)Point類(lèi),將方格看作一個(gè)點(diǎn),通過(guò)行與列來(lái)表示它的位置。
# 定義Point類(lèi)以表示方格的位置class Point: row=0 # 行 col=0 # 列 def __init__(self,row,col): # 行 列 self.row=row self.col=col |
(5)定義蛇頭、蛇身、食物的位置和顏色
之后,我們將蛇分為蛇頭和蛇身兩部分,設(shè)定其初始時(shí)各占一個(gè)和三個(gè)方格,而食物也作為一個(gè)元素占一格。
接著我們通過(guò)實(shí)例化類(lèi)的方式來(lái)定義他們的位置,同時(shí)也定義好他們顏色,其中,蛇身的位置我們以列表來(lái)表示,具體過(guò)程如下。
# 定義蛇頭、蛇身、食物的位置和顏色head = Point(row=int(ROW/2),col=int(COL/2)) # 定義蛇頭的小方格位置在第12行,第9列snakes=[ Point(row=head.row,col=head.col+1), # 定義蛇身1的小方格位置在第12行,第10列 Point(row=head.row,col=head.col+2), # 定義蛇身2的小方格位置在第12行,第11列 Point(row=head.row,col=head.col+3) # 定義蛇身3的小方格位置在第12行,第12列]food = Point(row=2,col=3) # 定義食物的小方格位置在第2行,第3列head_color=(65,105,225) # 定義蛇頭顏色snake_color=(204,204,204) # 定義蛇身顏色food_color=(255,10,10) # 定義食物顏色 |
(6)定義每個(gè)小方格的繪制方法
隨后,我們通過(guò)pygame庫(kù)繪制矩形的方法來(lái)繪制小方格,由于每個(gè)小方格的尺寸大小一致,僅位置和顏色不同,因此,我們可定義一個(gè)繪制方格的通用函數(shù),將位置和顏色作為兩個(gè)參數(shù)傳入,其中,各個(gè)方格的位置,我們可以通過(guò)其所在的行和列來(lái)確定。
# 定義每個(gè)小方格的繪制(包含兩個(gè)參數(shù):位置和顏色)def rect(point,color): left=point.col*cell_width # 定義小方格距離左邊緣的距離 top=point.row*cell_height # 定義小方格距離上邊緣的距離 pygame.draw.rect(window,color,(left,top,cell_width,cell_height)) # 在窗口上繪制矩形 |
(6)實(shí)例化Star類(lèi),并結(jié)束繪圖
最后,我們?cè)谥付ǖ奈恢蒙侠L制指定顏色的方格,分別代表蛇頭、蛇身和食物,而為了使其始終出現(xiàn),編程時(shí)我們將其放在循環(huán)中。
while run: # 游戲循環(huán) window.fill(bg_color) # fillcolor # 填充窗口的背景顏色 # 以小方格來(lái)定義蛇身、蛇頭和食物 for snake in snakes: rect(snake,snake_color) # 創(chuàng)建蛇身,顏色為snake_color rect(head,head_color) # 創(chuàng)建蛇頭,顏色為head_color rect(food,food_color) # 創(chuàng)建食物,顏色為food_color pygame.display.flip() # Refresh all displays to the window # 更新所有待顯示的內(nèi)容到屏幕 time.sleep(0.2) # delay 0.2 seconds |
Tips:完整示例程序如下:
'''在游戲窗口上添加蛇和食物'''import pygame # 導(dǎo)入pygame庫(kù)import time # 導(dǎo)入time庫(kù) pygame.init() # 游戲初始化W=240 # 定義寬H=320 # 定義高size=(240,320) # 定義尺寸window = pygame.display.set_mode(size) # 創(chuàng)建游戲窗口,尺寸為(240,320)bg_color=(255,255,255) # 定義背景色為白 # 將游戲窗口劃分為一個(gè)個(gè)小方格,每個(gè)方格的寬和高皆為15,共計(jì)24行,18列ROW=24 # 定義行數(shù),每格15*15,24行18列COL=18 # 定義列數(shù)cell_width=W/COL # 定義格子的寬cell_height=H/ROW # 定義格子的高 # 定義Point類(lèi)以表示方格的位置class Point: row=0 # 行 col=0 # 列 def __init__(self,row,col): # 行 列 self.row=row self.col=col# 定義蛇頭、蛇身、食物的位置和顏色head = Point(row=int(ROW/2),col=int(COL/2)) # 定義蛇頭的小方格位置在第12行,第9列snakes=[ Point(row=head.row,col=head.col+1), # 定義蛇身1的小方格位置在第12行,第10列 Point(row=head.row,col=head.col+2), # 定義蛇身2的小方格位置在第12行,第11列 Point(row=head.row,col=head.col+3) # 定義蛇身3的小方格位置在第12行,第12列]food = Point(row=2,col=3) # 定義食物的小方格位置在第2行,第3列head_color=(65,105,225) # 定義蛇頭顏色snake_color=(204,204,204) # 定義蛇身顏色food_color=(255,10,10) # 定義食物顏色 # 定義每個(gè)小方格的繪制(包含兩個(gè)參數(shù):位置和顏色)def rect(point,color): left=point.col*cell_width # 定義小方格距離左邊緣的距離 top=point.row*cell_height # 定義小方格距離上邊緣的距離 pygame.draw.rect(window,color,(left,top,cell_width,cell_height)) # 在窗口上繪制矩形,顏色為color run=True # 定義初始運(yùn)行狀態(tài)為T(mén)rue,表示運(yùn)行while run: # 游戲循環(huán) window.fill(bg_color) # fillcolor # 填充窗口的背景顏色 # 以小方格來(lái)定義蛇身、蛇頭和食物 for snake in snakes: rect(snake,snake_color) # 創(chuàng)建蛇身,顏色為snake_color rect(head,head_color) # 創(chuàng)建蛇頭,顏色為head_color rect(food,food_color) # 創(chuàng)建食物,顏色為food_color pygame.display.flip() # Refresh all displays to the window # 更新所有待顯示的內(nèi)容到屏幕 time.sleep(0.2) # delay 0.2 seconds |
2、程序運(yùn)行
STEP1:遠(yuǎn)程連接行空板
STEP2:運(yùn)行程序并觀察效果
點(diǎn)擊運(yùn)行后,觀察行空板,可以看到在游戲窗口內(nèi)顯示出了一條紅頭藍(lán)身的蛇,以及一顆黃色的食物。

任務(wù)描述3:設(shè)定游戲機(jī)制
在上個(gè)任務(wù)中,我們?cè)谟螒蚪缑鎯?nèi)添加了蛇和食物,但這還不夠,接下來(lái),我們將設(shè)定游戲機(jī)制,使得能通過(guò)行空板的板載按鍵a和b控制蛇左右移動(dòng)來(lái)吃食物,并且,食物由原來(lái)在固定位置生成改為隨機(jī)生成。
1、程序編寫(xiě)
STEP1:創(chuàng)建與保存項(xiàng)目文件
新建一個(gè)Python程序文件“main3.py”,雙擊打開(kāi)。
STEP2:程序編寫(xiě)
這個(gè)程序中,我們承任務(wù)2繼續(xù)編寫(xiě)。
(1)設(shè)定食物的隨機(jī)生成
這里,我們修改原來(lái)固定位置的食物,使其在屏幕窗口內(nèi)隨機(jī)位置生成。
# 定義食物的生成位置def gen_food(): pos = Point(row=random.randint(0,ROW-1),col=random.randint(0,COL-1)) # 定義食物的小方格位置在窗口內(nèi)隨機(jī)的地方 return posfood = gen_food() # 生成食物的位置 |
(2)定義事件監(jiān)測(cè)
為了能通過(guò)行空板上的按鍵來(lái)控制蛇的移動(dòng),我們首先需要定義一個(gè)事件監(jiān)測(cè),具體過(guò)程如下。
# 定義事件監(jiān)測(cè)def detect(): global direction global run events = pygame.event.get() # 獲取事件 for event in events: # 遍歷所有事件 if (event.type == pygame.QUIT): # 如果事件類(lèi)型為退出(關(guān)閉窗口) pygame.quit() # 退出游戲 run = 0 if (event.type == pygame.KEYDOWN): # 如果事件類(lèi)型為鍵盤(pán)按下 if (event.key == pygame.K_a): # 如果是按鍵a被按下 if (direction == 'up'): # 如果原來(lái)方向?yàn)閡p(向上) direction = 'left' # 將方向設(shè)為left(向左) elif (direction == 'left'): direction = 'down' elif (direction == 'down'): direction = 'right' elif (direction == 'right'): direction = 'up' print(direction) elif (event.key == pygame.K_b): # 如果是按鍵b被按下 if (direction == 'up'): # 如果原來(lái)方向?yàn)閡p(向上) direction = 'right' # 將方向設(shè)為right(向右) elif (direction == 'right'): direction = 'down' elif (direction == 'down'): direction = 'left' elif (direction == 'left'): direction = 'up' print(direction) |
(3)定義移動(dòng)方式并設(shè)定初始方向
之后,我們?cè)O(shè)定蛇的移動(dòng)方式,并定義初始方向?yàn)閘eft,具體過(guò)程如下。
# 定義移動(dòng)方式def move(): global direction if direction == 'left': # 如果方向?yàn)閘eft head.col-=1 # 設(shè)置蛇頭向左移動(dòng)一格(蛇頭所在的列數(shù)-1) elif direction == 'right': head.col+=1 elif direction == 'up': head.row-=1 elif direction == 'down': head.row+=1 direction = 'left' # 定義初始方向?yàn)閘eft |
(4)復(fù)制方格位置
由于蛇在吃到食物時(shí)蛇身會(huì)增加,從效果上看蛇頭的位置變成了蛇身第一格,因此,我們需要在定義Point類(lèi)時(shí),補(bǔ)充一個(gè)copy實(shí)例方法,達(dá)到復(fù)制方格自身位置的功能,以便后續(xù)在吃食物時(shí)調(diào)用。
# 定義Point類(lèi)以表示方格的位置class Point: row=0 # 行 col=0 # 列 def __init__(self,row,col): # 行 列 self.row=row self.col=col def copy(self): # 復(fù)制 return Point(row=self.row,col=self.col) |
(5)定義吃食物
接下來(lái),我們定義蛇吃食物的方法,具體過(guò)程如下。
# 定義吃食物def eat(): global food eating = (head.row == food.row and head.col == food.col) # 定義正在吃的形式:蛇頭的行列位置與食物相同 if eating : # 如果正在吃 food = Point(row=random.randint(0,ROW-1),col=random.randint(0,COL-1)) # 在隨機(jī)處再生成一顆食物 snakes.insert(0,head.copy()) # 處理蛇身:1、把原來(lái)的頭,插入到蛇身的最初位置(即在snakes蛇身列表的第0個(gè)位置增加一個(gè)元素) if not eating: # 如果不在吃了,吃完后 snakes.pop() #處理蛇身:2、把蛇身的最后一格移除(即移除snakes蛇身列表的最后一個(gè)元素) |
(6)循環(huán)調(diào)用
最后,我們將上述定義好的事件監(jiān)測(cè)、移動(dòng)、吃食物三個(gè)功能函數(shù)放入循環(huán)中,使其永久執(zhí)行。
while run: # 游戲循環(huán) window.fill(bg_color) # fillcolor # 填充窗口的背景顏色 # 以小方格來(lái)定義蛇身、蛇頭和食物 for snake in snakes: rect(snake,snake_color) # 創(chuàng)建蛇身,顏色為snake_color rect(head,head_color) # 創(chuàng)建蛇頭,顏色為head_color rect(food,food_color) # 創(chuàng)建食物,顏色為food_color eat() # 吃 detect() # 事件監(jiān)測(cè) move() # 移動(dòng) pygame.display.flip() # Refresh all displays to the window # 更新所有待顯示的內(nèi)容到屏幕 time.sleep(0.2) # 可修改延時(shí)的時(shí)間改變蛇的移動(dòng)速度,調(diào)整游戲難易度 |
Tips:完整示例程序如下:
'''控制蛇的移動(dòng)、生成隨機(jī)的食物、蛇吃食物'''import pygame # 導(dǎo)入pygame庫(kù)import random # 導(dǎo)入隨機(jī)數(shù)庫(kù)import time # 導(dǎo)入time庫(kù) pygame.init() # 游戲初始化W=240 # 定義寬H=320 # 定義高size=(240,320) # 定義尺寸window = pygame.display.set_mode(size) # 創(chuàng)建游戲窗口,尺寸為(240,320)bg_color=(255,255,255) # 定義背景色為白 # 將游戲窗口劃分為一個(gè)個(gè)小方格,每個(gè)方格的寬和高皆為15,共計(jì)24行,18列ROW=24 # 定義行數(shù),每格15*15,24行18列COL=18 # 定義列數(shù)cell_width=W/COL # 定義格子的寬cell_height=H/ROW # 定義格子的高 # 定義Point類(lèi)以表示方格的位置class Point: row=0 # 行 col=0 # 列 def __init__(self,row,col): # 行 列 self.row=row self.col=col def copy(self): # 復(fù)制 return Point(row=self.row,col=self.col) # 定義蛇頭、蛇身的位置和顏色head = Point(row=int(ROW/2),col=int(COL/2)) # 定義蛇頭的小方格位置在第12行,第9列snakes=[ # 定義蛇身列表 Point(row=head.row,col=head.col+1), # 定義蛇身1的小方格位置在第12行,第10列 Point(row=head.row,col=head.col+2), # 定義蛇身2的小方格位置在第12行,第11列 Point(row=head.row,col=head.col+3) # 定義蛇身3的小方格位置在第12行,第12列]# 定義食物的生成位置def gen_food(): pos = Point(row=random.randint(0,ROW-1),col=random.randint(0,COL-1)) # 定義食物的小方格位置在窗口內(nèi)隨機(jī)的地方 return posfood = gen_food() # 生成食物的位置 head_color=(65,105,225) # 定義蛇頭顏色snake_color=(204,204,204) # 定義蛇身顏色food_color=(255,10,10) # 定義食物顏色 # 定義每個(gè)小方格的繪制(包含兩個(gè)參數(shù):位置和顏色)def rect(point,color): left=point.col*cell_width # 定義小方格距離左邊緣的距離 top=point.row*cell_height # 定義小方格距離上邊緣的距離 pygame.draw.rect(window,color,(left,top,cell_width,cell_height)) # 在窗口上繪制矩形,顏色為color # 定義事件檢測(cè)def detect(): global direction global run events = pygame.event.get() # 獲取事件 for event in events: # 遍歷所有事件 #for event in pygame.event.get(): if (event.type == pygame.QUIT): # 如果事件類(lèi)型為退出(關(guān)閉窗口) pygame.quit() # 退出游戲 run = 0 if (event.type == pygame.KEYDOWN): # 如果事件類(lèi)型為鍵盤(pán)按下 if (event.key == pygame.K_a): # 如果是按鍵a被按下 if (direction == 'up'): # 如果原來(lái)方向?yàn)閡p(向上) direction = 'left' # 將方向設(shè)為left(向左) elif (direction == 'left'): direction = 'down' elif (direction == 'down'): direction = 'right' elif (direction == 'right'): direction = 'up' print(direction) elif (event.key == pygame.K_b): # 如果是按鍵b被按下 if (direction == 'up'): # 如果原來(lái)方向?yàn)閡p(向上) direction = 'right' # 將方向設(shè)為right(向右) elif (direction == 'right'): direction = 'down' elif (direction == 'down'): direction = 'left' elif (direction == 'left'): direction = 'up' print(direction) # 定義移動(dòng)方式def move(): global direction if direction == 'left': # 如果方向?yàn)閘eft head.col-=1 # 設(shè)置蛇頭向左移動(dòng)一格(蛇頭所在的列數(shù)-1) elif direction == 'right': head.col+=1 elif direction == 'up': head.row-=1 elif direction == 'down': head.row+=1 # 定義吃食物def eat(): global food eating = (head.row == food.row and head.col == food.col) # 定義正在吃的形式:蛇頭的行列位置與食物相同 if eating : # 如果正在吃 food = Point(row=random.randint(0,ROW-1),col=random.randint(0,COL-1)) # 在隨機(jī)處再生成一顆食物 snakes.insert(0,head.copy()) # 處理蛇身:1、把原來(lái)的頭,插入到蛇身的最初位置(即在snakes蛇身列表的第0個(gè)位置增加一個(gè)元素) if not eating: # 如果不在吃了,吃完后 snakes.pop() #處理蛇身:2、把蛇身的最后一格移除(即移除snakes蛇身列表的最后一個(gè)元素) direction = 'left' # 定義初始方向?yàn)閘eftrun = True # 定義初始運(yùn)行狀態(tài)為T(mén)rue,表示運(yùn)行while run: # 游戲循環(huán) window.fill(bg_color) # fillcolor # 填充窗口的背景顏色 # 以小方格來(lái)定義蛇身、蛇頭和食物 for snake in snakes: rect(snake,snake_color) # 創(chuàng)建蛇身,顏色為snake_color rect(head,head_color) # 創(chuàng)建蛇頭,顏色為head_color rect(food,food_color) # 創(chuàng)建食物,顏色為food_color eat() # 吃 detect() # 事件監(jiān)測(cè) move() # 移動(dòng) pygame.display.flip() # Refresh all displays to the window # 更新所有待顯示的內(nèi)容到屏幕 time.sleep(0.2) # 可修改延時(shí)改變蛇的移動(dòng)速度,調(diào)整游戲難易度 |
2、程序運(yùn)行
STEP1:遠(yuǎn)程連接行空板
STEP2:運(yùn)行程序并觀察效果
點(diǎn)擊運(yùn)行后,觀察行空板,可以看到在游戲窗口內(nèi)顯示出了一條紅頭藍(lán)身的蛇,以及一顆黃色的食物。隨后蛇向左移動(dòng),此時(shí),我們可通過(guò)按下板載按鍵a和b來(lái)分別控制蛇左轉(zhuǎn)和右轉(zhuǎn)。

任務(wù)描述4:結(jié)束游戲并計(jì)分
最后,我們?cè)谏鲜龉δ艿幕A(chǔ)上添加結(jié)束游戲和計(jì)分機(jī)制。
1、程序編寫(xiě)
STEP1:創(chuàng)建與保存項(xiàng)目文件
新建一個(gè)Python程序文件“main4.py”,雙擊打開(kāi)。
Step2:程序編寫(xiě)
(1)導(dǎo)入所需功能庫(kù)創(chuàng)建字體對(duì)象
由于需要顯示得分,因此,我們需要提前在定義背景顏色后創(chuàng)建一個(gè)字體對(duì)象。
font = pygame.font.SysFont('Arial', 20) # 設(shè)置字體 |
(2)結(jié)束游戲機(jī)制
之后,我們?cè)诔允澄锏墓δ芎笤俣x結(jié)束游戲的方式:要么蛇撞上窗口四周,要么撞上自身。同時(shí),我們?cè)O(shè)定在結(jié)束前顯示最終的游戲得分。
# 定義游戲結(jié)束def game_over(): global run dead=False # 定義一個(gè)狀態(tài)dead # 游戲結(jié)束方式1、撞墻 if head.col<0 or head.row<0 or head.col>=COL or head.row>=ROW: # 如果蛇頭的行和列在屏幕外 dead = True # 游戲結(jié)束方式2、撞自己 for snake in snakes: if head.col==snake.col and head.row==snake.row: # 如果蛇頭和蛇身位置相同 dead = True break if dead: # 如果狀態(tài)為dead score = font.render('Your Score is ' + str(10*len(snakes)-30), False, 'pink') # 計(jì)算得分 window.blit(score, (40,250)) # 在窗口上顯示得分 pygame.display.flip() # Refresh all displays to the screen # 更新所有顯示的內(nèi)容到屏幕 print("GG") # goodgame! =-= time.sleep(5) # delay 5 seconds run=False # set state False |
(3)循環(huán)執(zhí)行
最后,我們將上述定義好的結(jié)束游戲功能函數(shù)放入循環(huán)中,使其永久執(zhí)行。
while run: # 游戲循環(huán) window.fill(bg_color) # fillcolor # 填充窗口的背景顏色 # 以小方格來(lái)定義蛇身、蛇頭和食物 for snake in snakes: rect(snake,snake_color) # 創(chuàng)建蛇身,顏色為snake_color rect(head,head_color) # 創(chuàng)建蛇頭,顏色為head_color rect(food,food_color) # 創(chuàng)建食物,顏色為food_color eat() # 吃 detect() # 事件監(jiān)測(cè) move() # 移動(dòng) game_over() # 結(jié)束游戲 pygame.display.flip() # Refresh all displays to the window # 更新所有待顯示的內(nèi)容到屏幕 time.sleep(0.2) # delay 0.2 seconds # 可修改延時(shí)的時(shí)間改變蛇的移動(dòng)速度,調(diào)整游戲難易度 |
Tips:完整示例程序如下:
'''計(jì)分和結(jié)束游戲'''import pygame # 導(dǎo)入pygame庫(kù)import random # 導(dǎo)入隨機(jī)數(shù)庫(kù)import time # 導(dǎo)入 time庫(kù) pygame.init() # 游戲初始化W=240 # 定義寬H=320 # 定義高size=(240,320) # 定義尺寸window = pygame.display.set_mode(size) # 創(chuàng)建游戲窗口,尺寸為(240,320)bg_color=(255,255,255) # 定義背景色為白 font = pygame.font.SysFont('Arial', 20) # 創(chuàng)建字體對(duì)象 # 將游戲窗口劃分為一個(gè)個(gè)小方格,每個(gè)方格的寬和高皆為15,共計(jì)24行,18列ROW=24 # 定義行數(shù),每格15*15,24行18列COL=18 # 定義列數(shù)cell_width=W/COL # 定義格子的寬cell_height=H/ROW # 定義格子的高 # 定義Point類(lèi)以表示方格的位置class Point: row=0 # 行 col=0 # 列 def __init__(self,row,col): # 行 列 self.row=row self.col=col def copy(self): # 復(fù)制 return Point(row=self.row,col=self.col) # 定義蛇頭、蛇身的位置和顏色head = Point(row=int(ROW/2),col=int(COL/2)) # 定義蛇頭的小方格位置在第12行,第9列snakes=[ # 定義蛇身列表 Point(row=head.row,col=head.col+1), # 定義蛇身1的小方格位置在第12行,第10列 Point(row=head.row,col=head.col+2), # 定義蛇身2的小方格位置在第12行,第11列 Point(row=head.row,col=head.col+3) # 定義蛇身3的小方格位置在第12行,第12列]# 定義食物的生成位置def gen_food(): pos = Point(row=random.randint(0,ROW-1),col=random.randint(0,COL-1)) # 定義食物的小方格位置在窗口內(nèi)隨機(jī)的地方 return posfood = gen_food() # 生成食物的位置 head_color=(65,105,225) # 定義蛇頭顏色snake_color=(204,204,204) # 定義蛇身顏色food_color=(255,10,10) # 定義食物顏色 # 定義每個(gè)小方格的繪制(包含兩個(gè)參數(shù):位置和顏色)def rect(point,color): left=point.col*cell_width # 定義小方格距離左邊緣的距離 top=point.row*cell_height # 定義小方格距離上邊緣的距離 pygame.draw.rect(window,color,(left,top,cell_width,cell_height)) # 在窗口上繪制矩形,顏色為color # 定義事件檢測(cè)def detect(): global direction global run events = pygame.event.get() # 獲取事件 for event in events: # 遍歷所有事件 #for event in pygame.event.get(): if (event.type == pygame.QUIT): # 如果事件類(lèi)型為退出(關(guān)閉窗口) pygame.quit() # 退出游戲 run = 0 if (event.type == pygame.KEYDOWN): # 如果事件類(lèi)型為鍵盤(pán)按下 if (event.key == pygame.K_a): # 如果是按鍵a被按下 if (direction == 'up'): # 如果原來(lái)方向?yàn)閡p(向上) direction = 'left' # 將方向設(shè)為left(向左) elif (direction == 'left'): direction = 'down' elif (direction == 'down'): direction = 'right' elif (direction == 'right'): direction = 'up' print(direction) elif (event.key == pygame.K_b): # 如果是按鍵b被按下 if (direction == 'up'): # 如果原來(lái)方向?yàn)閡p(向上) direction = 'right' # 將方向設(shè)為right(向右) elif (direction == 'right'): direction = 'down' elif (direction == 'down'): direction = 'left' elif (direction == 'left'): direction = 'up' print(direction) # 定義移動(dòng)方式def move(): global direction if direction == 'left': # 如果方向?yàn)閘eft head.col-=1 # 設(shè)置蛇頭向左移動(dòng)一格(蛇頭所在的列數(shù)-1) elif direction == 'right': head.col+=1 elif direction == 'up': head.row-=1 elif direction == 'down': head.row+=1 # 定義吃食物def eat(): global food eating = (head.row == food.row and head.col == food.col) # 定義正在吃的形式:蛇頭的行列位置與食物相同 if eating : # 如果正在吃 food = Point(row=random.randint(0,ROW-1),col=random.randint(0,COL-1)) # 在隨機(jī)處再生成一顆食物 snakes.insert(0,head.copy()) # 處理蛇身:1、把原來(lái)的頭,插入到蛇身的最初位置(即在snakes蛇身列表的第0個(gè)位置增加一個(gè)元素) if not eating: # 如果不在吃了,吃完后 snakes.pop() #處理蛇身:2、把蛇身的最后一格移除(即移除snakes蛇身列表的最后一個(gè)元素) # 定義游戲結(jié)束def game_over(): global run dead=False # 定義一個(gè)狀態(tài)dead # 游戲結(jié)束方式1、撞墻 if head.col<0 or head.row<0 or head.col>=COL or head.row>=ROW: # 如果蛇頭的行和列在屏幕外 dead = True # 游戲結(jié)束方式2、撞自己 for snake in snakes: if head.col==snake.col and head.row==snake.row: # 如果蛇頭和蛇身位置相同 dead = True break if dead: # 如果狀態(tài)為dead score = font.render('Your Score is ' + str(10*len(snakes)-30), False, 'pink') # 計(jì)算得分 window.blit(score, (40,250)) # 在窗口上顯示得分 pygame.display.flip() # Refresh all displays to the screen # 更新所有顯示的內(nèi)容到屏幕 print("GG") # goodgame! =-= time.sleep(5) # delay 5 seconds run=False # set state False direction = 'left' # 定義初始方向?yàn)閘eftrun = True # 定義初始運(yùn)行狀態(tài)為T(mén)rue,表示運(yùn)行while run: # 游戲循環(huán) window.fill(bg_color) # fillcolor # 填充窗口的背景顏色 # 以小方格來(lái)定義蛇身、蛇頭和食物 for snake in snakes: rect(snake,snake_color) # 創(chuàng)建蛇身,顏色為snake_color rect(head,head_color) # 創(chuàng)建蛇頭,顏色為head_color rect(food,food_color) # 創(chuàng)建食物,顏色為food_color eat() # 吃 detect() # 事件監(jiān)測(cè) move() # 移動(dòng) game_over() # 結(jié)束游戲 pygame.display.flip() # Refresh all displays to the window # 更新所有待顯示的內(nèi)容到屏幕 time.sleep(0.2) # delay 0.2 seconds # 可修改延時(shí)的時(shí)間改變蛇的移動(dòng)速度,調(diào)整游戲難易度 |
2、程序運(yùn)行
STEP1:遠(yuǎn)程連接行空板
STEP2:運(yùn)行程序并觀察效果
運(yùn)行程序后,我們可通過(guò)板載按鍵a、b控制蛇的移動(dòng),當(dāng)蛇撞上自身或撞上窗口四邊時(shí),游戲結(jié)束,此時(shí)可看到我們游戲的最終得分。


挑戰(zhàn)自我
1、和同學(xué)比一比,看誰(shuí)的得分更高吧!
2、嘗試減小屏幕刷新的時(shí)間間隔,使蛇移動(dòng)得更快,加大難度試一試吧!
3、想一想,我們是否可以給不同難度的游戲設(shè)置關(guān)卡呢,自己動(dòng)手修改程序,練習(xí)一下吧!
審核編輯:符乾江
-
python
+關(guān)注
關(guān)注
56文章
4825瀏覽量
86445 -
DFRobot
+關(guān)注
關(guān)注
4文章
1160瀏覽量
10671
發(fā)布評(píng)論請(qǐng)先 登錄
視頻詳解:上海尤老師verilog入門(mén)到實(shí)戰(zhàn)第六課
【FPGA DEMO】Lab 9:貪吃蛇小游戲
基于stm32的貪吃蛇小游戲的設(shè)計(jì)資料分享
單片機(jī)入門(mén)教程第六課-單片機(jī)的內(nèi)外部結(jié)構(gòu)分析(四)
貪吃蛇游戲設(shè)計(jì)貪吃蛇收尾基本完成
基于嵌入式linux開(kāi)發(fā)板的貪吃蛇游戲運(yùn)行
STM32+LCD實(shí)現(xiàn)簡(jiǎn)單的貪吃蛇小游戲

基于stm32的貪吃蛇小游戲

基于STM32的貪吃蛇小游戲

【STM32】貪吃蛇小游戲

評(píng)論