如果你沒有任何編程經驗,而且想嘗試一下學習編程開發,這個系列教程一定適合你,它將帶你學習最基本的Python語法,並讓你掌握小游戲的開發技巧。你所需要的,就是付出一些時間和耐心來嘗試這些代碼和操作。
@[top]
一、准備工作
1 下載安裝 python
2 下載安裝 VS code
編輯器
安裝時,要注意勾選 添加到path
3 安裝pygame模塊
- 在VisualStudioCode的頂部菜單【
Terminal-New Teminal
】打開命令行終端,然后輸入命令python -m pip install --upgrade pip
,回車,等待完成。
- 然后同樣輸入命令pip install pygame,等待完成安裝,可能需要幾分鍾
二、創建項目
-
在桌面上創建一個文件夾
mygame
,然后在VSCode中使用菜單【File-Open Folder】,選擇mygame
文件夾,VSCode左側將會出現EXPLORER導航欄。 -
在左側導航欄中,【右鍵-New File】創建文件
main.py
。
- 將下面的代碼粘貼到右側`main.py`文件中。
import pygame
import sys
pygame.display.set_mode([600,400])
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
在這里我還是要說一下,文中素材以及可執行代碼可以加群:456926667,獲取,這個是我創建的一個針對0基礎的伙伴一個交流群,下個文章我會更新關於pycharm版本的打地鼠。
- 運行代碼。
* 仍然【Terminal-New terminal】終端中輸入命令`python main.py`,這將運行我們上面的代碼,看到彈出一個黑色窗口。
三、可選操作
-
執行上面的操作的時候,VSCode的右下角會經常彈出一些提示,如果有【Install】字樣,可以放心的點擊它進行安裝更多內容。
-
也可以從左側欄點擊圖標打開【EXTENSIONS】,然后搜索
@id:ms-python.python
,點擊找到的結果,右側再點擊【Install】按鈕進行安裝。安裝之后main.py
文件的右上角就會出現三角形運行按鈕,點擊它同樣可以運行代碼,相當於終端中輸入python main.py
。
-
pip install ...
安裝命令太慢。Windows用戶,可以從上面的網盤中下載pip.ini
文件,然后在【C盤-用戶-用戶名】文件夾下面創建pip
文件夾,再把下載的pip.ini
文件拷貝進去,此后再運行pip install ...
安裝速度就會快很多。 -
對於蘋果用戶就麻煩很多。先在終端執行
cd ~
切換到用戶文件夾,然后執行mkdir .pip
創建.pip
文件夾,它是隱身的,我們打開訪達,從菜單執行【前往-前往文件夾...】,前往~/.test
目錄,把下載的pip.conf
文件粘貼進去,搞定。
pip.ini
或者pip.conf
文件是把原來pip
默認從國外下載安裝改成了從國內下載,所以速度會變快很多。
-
其中
import
是導入我們要使用的外部代碼模塊,pygame
當然是必須的,sys
是system系統
的簡寫,因為我們的游戲要運行在系統(windows或者蘋果macOS)上面,所以我們會用到系統的一些命令,比如下面的sys.exit()
這個命令。 -
pyagme.display.set_mode([600,400])
,這里的[600,400]
是一對數字組合在一起的,叫二元數組,這里它表示寬600,高400的一個矩形。整句話就是設置要彈出的窗口的大小,display顯示
,set設置
,mode模式
。 -
while 1:...當是1的時候,就...
,1在代碼里面表示正確的、真的、存在的,相反,0表示錯誤、假的、不存在的。while 1:do something
那么something就會做,如果while 0: do something
那么就不會做了。 -
for ... sys.exit()
這一段暫時可以不深究,只是固定格式。只要知道它表示游戲程序運行結束的時候系統把窗口也關掉,清理好計算機不要留痕跡,exit退出
。
游戲開發的思路
游戲開發都有固定的套路,無論是打地鼠、憤怒的小鳥,還是西瓜忍者,甚至是王者榮耀這樣的大型游戲,他們大致都遵循下面幾個思路:
-
創建一個地圖場景,上面可能有些道具。
比如幾個地鼠洞,一些可以放小豬的木盒子,甚至非常復雜的山谷地形,上面還有很多野怪。
這些地圖上的元素一般都是被動的,就是你不去靠近或招惹野怪的話,它們不會互相打起來自相殘殺,同樣,小鳥還沒發射的時候,木盒子也不會自己倒塌。 -
創建至少一個玩家可以控制的元素,它可以和地圖場景發生交互。
這個可以被控制的元素我們稱為玩家角色。在打地鼠游戲中這個角色就是一個錘子,憤怒的小鳥中這個角色其實是彈弓,彈出的小鳥其實是個道具,在王者榮耀游戲中玩家的角色就是自己的英雄。
-
必須要有評判標准,用來衡量輸贏勝敗。
玩家控制的角色和地圖場景進行交互,發生反應,對應的也必須要有一個評判標准,比如計算3分鍾內擊中地鼠的次數,或者計算砸死的綠豬的數量,或者是打野怪獲得的經驗,這些規則一定要清晰而且不能互相矛盾。
大多數游戲都有輸贏勝敗,而勝敗往往本質上只是誰的積分首先達到某個臨界點。可以是某個關鍵道具的變化,比如對戰游戲中塔被摧毀,也可以是玩家角色的屬性變化,比如格斗游戲中被擊殺;也可以只是純粹的某項積分評比,用排行榜代替輸贏。
游戲開發的技術點
-
要能夠在窗口內繪制圖形。
可以是直接用代碼繪制幾何圖形,也可以是載入圖片顯示內容。
-
要能用代碼控制每個元素(道具和角色)的動畫。
動畫就是一組圖片不停地輪番變化。要能用代碼控制播放和停止每個元素的動畫,還能在不同動畫之間快速切換。
-
能夠接收用戶的控制,並借此影響游戲中的元素。
知道用戶什么時候按了鍵盤,什么時候點了鼠標,按了哪個按鍵,鼠標左鍵還是右鍵?我們經常把這些操作稱之為交互事件。
-
能夠對游戲中各種元素產生的有效數據進行計算和管理。
玩家角色一刀砍下去,怪物的血量減少了100點,這個就是數據,而且是很有用的數據,沒有這個數據的話怪物可能永遠砍不死了。
有時候這些數據要保存好,讓用戶下一次打開游戲的時候仍然看到自己的等級和裝備都還存在。有些時候這些數據要及時清理,比如新的一局又開始了,地圖上的道具和角色都要恢復原樣。
打地鼠游戲
我們可以把經典的打地鼠游戲簡化概括為:
- 地圖和道具:隨機位置出現地鼠圖形
- 交互角色:控制錘子圖形,點擊地鼠圖形使其消失
- 積分輸贏:限定時間內擊中地鼠圖形的次數
核心玩法簡化成一句話就是:點擊隨機出現圖形。
繪制地鼠
我們用一個藍色的圓形代表地鼠。那怎么在窗口中繪制一個圓形呢?
可以百度【pygame 畫圓圈】類似的關鍵字,可以查到要使用pygame.draw.circle
語句,它的具體語法可以從官方說明文檔中找到,英文版詳細說明點這里。
我們查到它的語法是:
pygame.draw.circle()
circle(surface, color, center, radius) -> Rect
這表示draw.circle()
需要四個參數,分別是surface表面,color顏色,center中心點,radius半徑
。
我們繼續看surface
參數的說明:
surface (Surface) -- surface to draw on
聽上去像是畫布,——先要有個畫布才能在上面畫圓。
點擊Surface鏈接,找到更進一步說明:
Surface((width, height), flags=0, depth=0, masks=None) -> Surface
結尾的->Surface
表示Surface((width....)
這句話可以生成一個Surface表面,我們可以用下面的語句捕捉到這個生成的表面:
sur=pygame.Surface((600, 400)
這樣,sur
就是我們生成的表面了。
顏色和位置
再返回來看color
參數:
color (Color or int or tuple(int, int, int, [int]))
-- color to draw with,
the alpha value is optional if using a tuple (RGB[A])
很明顯它是表示畫什么顏色的圓。tuple(int, int, int, [int])
表示這里需要三個整數int
一起表示顏色,RGB
是指red紅,green綠,blue藍,alpha透明度
:
clr=(0,0,255) #藍色
對於center
中心位置我們也可以用同樣的方法得到,這里的Vector2
表示二元向量,及橫向x和豎向y的位置:
pos=pygame.vector2(300,200) #窗口中央
繪制圓形
參數都具備了,那么就可以開始畫圓了。運行下面的代碼:
import pygame
import sys
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
sur = pygame.Surface([600, 400]) # 繪制背景容器
clr = (0, 0, 255)
pos = (300,200)
rad = 100
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# 每幀循環執行的代碼
pygame.draw.circle(sur, clr, pos, 100# 繪制圓
# 刷新畫面
window.blit(sur, (0, 0))
pygame.display.flip()
注意這里最底部刷新畫面的兩行,其中window.blit(sur, (0, 0))
表示把我們繪制好的表面sur
刷新到window
窗口中;pygame.display.flip()
表示進行窗口刷新。
隨機出現
隨機出現就是隨機位置,我們必須確保每一次花圓的pos
位置都不同,而且應該是固定的幾個地鼠洞位置。——別忘了我們要做打地鼠游戲。
假設有6個地鼠位置pos
分別是[200,200],[300,200],[400,200],[200,300],[300,300],[400,300]
,那么如何隨機取到6個中一個呢?也就是如何隨機取到1~6其中的一個數字即可。
我們可以百度【python 隨機數】查到需要使用random
模塊,這是python自帶的模塊,不需要再重新pip install
。
如果搜索【python random document】可以查找到官方的語法說明,如下:
random.randint(a, b)
Return a random integer N such that a <= N <= b.
Alias for randrange(a, b+1).
這是說可以隨機生成a
和b
之間的一個數字。也可以從中文的菜鳥教程網
學習到這個知識。
新建一個test.py
文件,我們進行測試:
import random
a = random.randint(0, 5)
print(a)
每次運行都能生成不同的數字。
繼續測試:
import random
a = random.randint(0, 6)
pos6=[[200,200],[300,200],[400,200],[200,300],[300,300],[400,300]]
print(pos6[a])
這里的pos6[a]
表示pos6
的六個位置中的第a
個。運行這個代碼就會每次生成不同的位置。
測試成功之后我們把它拷貝到剛才的畫圓代碼中,得到:
import pygame
import sys
import random
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
sur = pygame.Surface([600, 400]) # 繪制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # !!六個位置
rad = 100
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# 每幀循環執行的代碼
sur.fill((0, 0, 0)) # !!用黑色覆蓋前一幀的畫面,實現刷新
a = random.randint(0, 5) # !!隨機0到5
pygame.draw.circle(sur, clr, pos6[a], 100) # !!使用隨機位置
# 刷新畫面
window.blit(sur, (0, 0))
pygame.display.flip()
注意新增了sur.fill...
一行,這是用黑色(0,0,0)
來清理掉上一幀的內容,避免出現多個圓。
隔n幀刷新
上面的代碼運行之后會看到藍色的圓四處亂跳,太快了,我們希望改變位置之后能停一下,等我們錘它。
我們需要畫面的圓每隔n幀再隨機變換一次,而不是現在的每幀都隨機變。思路是這樣的:我們設定一個計數器,開始是0,每幀都給它增加1,就是0,1,2,3,4...
直到它增到到超過50,這時候我們就改變圓的位置並同時把計數器重置為0。
代碼如下:
import pygame
import sys
import random
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
sur = pygame.Surface([600, 400]) # 繪制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # 六個位置
rad = 100
tick=0 #!!計數器
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# 每幀循環執行的代碼
if tick>50: #每50次刷新變換一次
sur.fill((0, 0, 0)) # 用黑色覆蓋前一幀的畫面,實現刷新
a = random.randint(0, 5) # 隨機0到5
pygame.draw.circle(sur, clr, pos6[a], 100) # 使用隨機位置
tick=0
else: #!!不刷新變換的時候
tick=tick+1 #!!增加計數器
# 刷新畫面
window.blit(sur, (0, 0))
pygame.display.flip()
增加交互點擊
當用戶點擊畫面的時候,我們要知道它點擊了哪里,是否點擊到了我們畫的圓上面。
百度搜索【pygame 點擊】可以找到相關資源,也可以直接在官方說明文檔中找到。
思路是我們添加對event.type
事件類型的實時監測,一旦發現點擊事件就獲取位置坐標。代碼如下:
import pygame
import sys
import random
from pygame.locals import * # 引入鼠標事件類型
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
sur = pygame.Surface([600, 400]) # 繪制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # 六個位置
rad = 100
tick = 0 # !!計數器
pos = pos6[0] # !!在外面記錄圓的位置
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # !!如果是鼠標按下事件
mpos = pygame.mouse.get_pos() # !!獲取鼠標位置
print(mpos)
# 每幀循環執行的代碼
if tick > 50: # 每50次刷新變換一次
sur.fill((0, 0, 0)) # 用黑色覆蓋前一幀的畫面,實現刷新
a = random.randint(0, 5) # 隨機0到5
pos = pos6[a] # !!更新外部記錄的圓的位置
pygame.draw.circle(sur, clr, pos, 100) # !!使用隨機位置
tick = 0 # 重置計數器
else: # !!不刷新變換的時候
tick = tick+1 # !!增加計數器
# 刷新畫面
window.blit(sur, (0, 0))
pygame.display.flip()
運行這個代碼,任意點擊屏幕上的時候就會打印出檔期鼠標點擊的位置。
距離測量
知道當前圓的位置pos
,也知道當前點擊的位置mpos
,這樣我們就可以計算出兩點之間的距離,距離大於圓半徑的就是沒有點到地鼠,距離小於半徑的就是點到地鼠了。
百度搜索【pygame 兩點距離】可以搜到一些計算距離的方法,我們這里使用pygame
官方提供的方法,測試下面代碼:
import pygame
a=pygame.math.Vector2.length(pygame.math.Vector2(3,4))
print(a)
它會輸出5(勾三股四玄五)。這里的(3,4)
是pos
和mpos
相減得到的差。
把這個思路帶入原來的代碼,得到:
import pygame
import sys
import random
from pygame.locals import * # 引入鼠標事件類型
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
sur = pygame.Surface([600, 400]) # 繪制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # 六個位置
rad = 50
tick = 0 # 計數器
pos = pos6[0] # 外面記錄圓的位置
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠標按下事件
mpos = pygame.mouse.get_pos() # 獲取鼠標位置
dis = pygame.math.Vector2(
mpos[0]-pos[0], mpos[1]-pos[1]) # !!計算坐標差
len = pygame.math.Vector2.length(dis) # !!計算距離
if len < rad:
tick = 51 # !!立即變換位置
# 每幀循環執行的代碼
if tick > 50: # 每50次刷新變換一次
sur.fill((0, 0, 0)) # 用黑色覆蓋前一幀的畫面,實現刷新
a = random.randint(0, 5) # 隨機0到5
pos = pos6[a] # 更新外部記錄的圓的位置
pygame.draw.circle(sur, clr, pos, 100) # 使用隨機位置
tick = 0 # 重置計數器
else: # 不刷新變換的時候
tick = tick+1 # 增加計數器
# 刷新畫面
window.blit(sur, (0, 0))
pygame.display.flip()
在這里我們設定如果距離長度len
小於圓半徑rad
,那么就立即設置tick=51
使它大於50,立即進行隨機位置變換。
截止到這里運行上面的代碼,可以實現隨機出現地鼠(圓)並能夠點擊使它消失,這也實現了游戲的最基本邏輯功能。后續我們將進一步編寫更多內容,讓它更完善一些。
記錄分數
計算數字增加很容易,設定一個score=0
,然后擊中地鼠的時候增加1就可以了。但是,如何把它顯示到屏幕上呢?
可以百度搜索【pygame 顯示文字】然后就可以找到大致方法,我們先進行一些測試:
import pygame
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
# 顯示文字
pygame.font.init() # !!初始化文字
font = pygame.font.SysFont('微軟雅黑', 30) # !!設定字體和字號
sur = font.render("Hello World!!{}".format(999), False, (255, 0, 0)) # !!生成w文字表面
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
window.blit(sur, (200, 10)) # !!增加分數表面
pygame.display.flip()
這段代碼中可以看到pygame繪制文字分三步:
pygame.font.init()
先要初始化pygame.font.SysFont('微軟雅黑', 30)
設定字體和字號大小font.render("Hello World!!{}".format(999), False, (255, 0, 0))
生成一個Surface表面
當然,最后別忘了把表面放到窗口里window.blit(sur, (200, 10))
運行上面的代碼得到一個窗口如下:
我們根據這個經驗改進的代碼:
import pygame
import sys
import random
from pygame.locals import * # 引入鼠標事件類型
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
sur = pygame.Surface([600, 400]) # 繪制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # 六個位置
rad = 50
tick = 0 # 計數器
pos = pos6[0] # 外面記錄圓的位置
# 分數
score = 0 # !!分數計數
pygame.font.init() # !!初始化文字
score_font = pygame.font.SysFont('微軟雅黑', 30) # !!設定字體和字號
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成計數表面
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠標按下事件
mpos = pygame.mouse.get_pos() # 獲取鼠標位置
dis = pygame.math.Vector2(
mpos[0]-pos[0], mpos[1]-pos[1]) # 計算坐標差
len = pygame.math.Vector2.length(dis) # 計算距離
if len < rad:
tick = 1000 # 立即變換位置
score = score+1 # 計分增加
# 每幀循環執行的代碼
if tick > 50: # 每50次刷新變換一次
score_sur = score_font.render(
str(score), False, (255, 0, 0)) # !!重新生成分數文字表面
sur.fill((0, 0, 0)) # 用黑色覆蓋前一幀的畫面,實現刷新
a = random.randint(0, 5) # 隨機0到5
pos = pos6[a] # 更新外部記錄的圓的位置
pygame.draw.circle(sur, clr, pos, 50) # 使用隨機位置
tick = 0 # 重置計數器
else: # 不刷新變換的時候
tick = tick+1 # 增加計數器
# 刷新畫面
window.blit(sur, (0, 0))
window.blit(score_sur, (200, 10)) # !!增加分數表面
pygame.display.flip()
運行上面的代碼,可以用鼠標點擊跳動的藍色圓,每次擊中就能獲得1分,實時顯示在頂部。
關於文字的更多內容可以參考官方文檔說明。
鼠標指針變錘子
現在窗口中顯示的仍然是鼠標,而不是錘子,下面我們來看如何把鼠標變為一個特定的圖形。
pygame關於鼠標控制的模塊是pygame.mouse
,官方說明文檔看這里。
我們可以用pygame.mouse.set_visible(False)
來隱藏鼠標,但這樣一來我們就看不到鼠標無法操作了。
不過不要緊,我們之前還記得當鼠標點擊的時候有一個mpos = pygame.mouse.get_pos()
可以獲取當前鼠標的位置,同樣我們可以在鼠標移動的時候獲取鼠標的位置,然后在這個位置上畫一個紅色圓圈代表鼠標。
測試下面的代碼:
import pygame
from pygame.locals import *
pygame.init()
window = pygame.display.set_mode([600, 400])
pygame.mouse.set_visible(False) # 隱藏鼠標
sur = pygame.Surface([600, 400])
mpos = [300, 200] # 記錄鼠標位置
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEMOTION: # 當鼠標移動的時候
mpos = pygame.mouse.get_pos() # 更新鼠標位置
sur.fill((0, 0, 0)) # 填充黑色
pygame.draw.circle(sur, (255, 0, 0), mpos, 10) # 在鼠標位置畫紅色圓
window.blit(sur, (0, 0))
pygame.display.flip()
運行這個代碼將,當鼠標划到窗口上面的時候就會有一個紅點跟着鼠標移動,紅點代替了原來的指針。
我們把這個紅點鼠標代碼放入到游戲中,得到下面的代碼:
import pygame
import sys
import random
from pygame.locals import * # 引入鼠標事件類型
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
sur = pygame.Surface([600, 400]) # 繪制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # 六個位置
rad = 50
tick = 0 # 計數器
pos = pos6[0] # 外面記錄圓的位置
# 分數
score = 0 # 分數計數
pygame.font.init() # 初始化文字
score_font = pygame.font.SysFont('微軟雅黑', 30) # !!設定字體和字號
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成計數表面
# 鼠標
pygame.mouse.set_visible(False) # !!隱藏鼠標
mpos = [300, 200] # !!記錄鼠標位置
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠標按下事件
mpos = pygame.mouse.get_pos() # 獲取鼠標位置
dis = pygame.math.Vector2(
mpos[0]-pos[0], mpos[1]-pos[1]) # 計算坐標差
len = pygame.math.Vector2.length(dis) # 計算距離
if len < rad:
tick = 1000 # 立即變換位置
score = score+1 # 計分增加
elif event.type == MOUSEMOTION: # !!當鼠標移動的時候
mpos = pygame.mouse.get_pos() # !!更新鼠標位置
# 每幀循環執行的代碼
if tick > 50: # 每50次刷新變換一次
score_sur = score_font.render(
str(score), False, (255, 0, 0)) # 重新生成分數文字表面
a = random.randint(0, 5) # 隨機0到5
pos = pos6[a] # 更新外部記錄的圓的位置
tick = 0 # 重置計數器
else: # 不刷新變換的時候
tick = tick+1 # 增加計數器
# 繪制鼠標
sur.fill((0, 0, 0)) # !用黑色覆蓋前一幀的畫面,實現刷新
pygame.draw.circle(sur, clr, pos, 50) # !使用隨機位置畫地鼠
pygame.draw.circle(sur, (255, 0, 0), mpos, 10) # !!在鼠標位置畫紅色圓
# 刷新畫面
window.blit(sur, (0, 0))
window.blit(score_sur, (200, 10)) # 增加分數表面
pygame.display.flip()
主義者了把sur.fill
和原來畫地鼠藍圓的代碼移到了下面,和畫鼠標紅點的代碼放在了一起,這樣把繪圖內容放在一起更加合理。
限定每局時間
我們有很多辦法限定每局的長度,比如計時限定1分鍾,或者限定地鼠跳出總計100次。我們這里使用第二種限制,跳出100次就結束並統計分數。
添加一個計數器times=0
,然后每次隨機位置都給它增加1,當times>100
的時候,我們就結束游戲並顯示結束畫面統計戰果。
具體的代碼沒有新的內容,不多解釋,直接上結果:
import pygame
import sys
import random
from pygame.locals import * # 引入鼠標事件類型
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
sur = pygame.Surface([600, 400]) # 繪制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # 六個位置
rad = 50
tick = 0 # 計數器
pos = pos6[0] # 外面記錄圓的位置
# 分數
score = 0 # 分數計數
pygame.font.init() # 初始化文字
score_font = pygame.font.SysFont('微軟雅黑', 30) # !!設定字體和字號
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成計數表面
# 鼠標
pygame.mouse.set_visible(False) # !!隱藏鼠標
mpos = [300, 200] # !!記錄鼠標位置
times = 0 # 地鼠跳出的次數
times_max=10 #最多次數
tick_max=15 #地鼠每次跳多少幀
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠標按下事件
mpos = pygame.mouse.get_pos() # 獲取鼠標位置
dis = pygame.math.Vector2(
mpos[0]-pos[0], mpos[1]-pos[1]) # 計算坐標差
len = pygame.math.Vector2.length(dis) # 計算距離
if len < rad:
tick = 1000 # 立即變換位置
score = score+1 # 計分增加
elif event.type == MOUSEMOTION: # !!當鼠標移動的時候
mpos = pygame.mouse.get_pos() # !!更新鼠標位置
if times > times_max:
# 顯示結束畫面
sur.fill((0, 0, 0))
pygame.mouse.set_visible(True)
sur.fill((0, 0, 0))
end_font = pygame.font.SysFont('微軟雅黑', 80) # !!設定字體和字號
end_sur = score_font.render("Your Score is:{}/{}!".format(score,times_max), False, (255, 0, 0)) # !!生成計數表面
window.blit(sur, (0, 0))
window.blit(end_sur, (100, 100)) # 增加分數表面
pygame.display.flip()
else:
# 每幀循環執行的代碼
if tick > tick_max: # 每50次刷新變換一次
times=times+1 #增加計次
score_sur = score_font.render(
str(score), False, (255, 0, 0)) # 重新生成分數文字表面
a = random.randint(0, 5) # 隨機0到5
pos = pos6[a] # 更新外部記錄的圓的位置
tick = 0 # 重置計數器
else: # 不刷新變換的時候
tick = tick+1 # 增加計數器
# 繪制鼠標
sur.fill((0, 0, 0)) # !用黑色覆蓋前一幀的畫面,實現刷新
pygame.draw.circle(sur, clr, pos, 50) # !使用隨機位置畫地鼠
pygame.draw.circle(sur, (255, 0, 0), mpos, 10) # !!在鼠標位置畫紅色圓
# 刷新畫面
window.blit(sur, (0, 0))
window.blit(score_sur, (200, 10)) # 增加分數表面
pygame.display.flip()
運行這個代碼,用鼠標點擊藍圓,藍圓跳動10次之后結束,然后顯示擊中的次數。你可以通過調整tick_max
的數字讓圓跳動的更快或更慢,調整times_max=100
來讓地鼠跳動100次后再結束。
現在我們的地鼠游戲已經有些模樣了,但還都是藍色紅色的圓圈和圓點,下一篇我們來改變成為圖片。
中文字體
在上一節中我們只使用了英文字體,怎么顯示中文字體呢?
直接下載網盤里面的文件,放在你的main.py
一起,將原來的
score_font = pygame.font.SysFont('微軟雅黑', 30)
修改為:
score_font = pygame.font.Font('MicrosoftYaqiHeiLight-2.ttf', 30)
然后在render
里面使用中文就可以正常顯示了:
end_sur = score_font.render("你的得分:{}/{}!".format(score,times_max), False, (255, 0, 0))
另外,也可以使用系統的中文字體,但是我們不清楚系統里面到底裝了哪些字體,可以用
print(pygame.font.get_fonts())
將所有系統字體都打印出來,然后只能從名字猜出哪些是中文字體了,注意系統字體還是要用font.SysFont
而不只是font.Font
。
顯示背景圖片
這是我們的背景圖片dds-map.jpg
:
我們可以用map=pygame.image.load('dds-map.jpg')
把圖片讀取到代碼里面。
更多官方關於圖片的操作說明看這里
注意pygame.image.load()
得到的是一個表面surface
,我們可以直接把它blit
到窗口wind
,也可以把它blit
到。
這里是完整代碼:
import pygame
import sys
import random
from pygame.locals import * # 引入鼠標事件類型
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
sur = pygame.Surface([600, 400]) # 繪制背景容器
clr = (0, 0, 255)
posAll = [[100, 150], [300, 150], [500, 150], [
200, 300], [400, 300]] # 六個位置
rad = 50
tick = 0 # 計數器
pos = posAll[0] # 外面記錄圓的位置
# 分數
score = 0 # 分數計數
pygame.font.init() # 初始化文字
score_font = pygame.font.Font('MicrosoftYaqiHeiLight-2.ttf', 30) # !!設定字體和字號
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成計數表面
# 鼠標
pygame.mouse.set_visible(False) # !!隱藏鼠標
mpos = [300, 200] # !!記錄鼠標位置
times = 0 # 地鼠跳出的次數
times_max=10 #最多次數
tick_max=30 #地鼠每次跳多少幀
map=pygame.image.load('dds-map.jpg')#!!讀取圖片
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠標按下事件
dis = pygame.math.Vector2(
mpos[0]-pos[0], mpos[1]-pos[1]) # 計算坐標差
len = pygame.math.Vector2.length(dis) # 計算距離
if len < rad:
tick = 1000 # 立即變換位置
score = score+1 # 計分增加
elif event.type == MOUSEMOTION: # 當鼠標移動的時候
mpos = pygame.mouse.get_pos() # 更新鼠標位置
if times >= times_max:
# 顯示結束畫面
sur.fill((0, 0, 0)) #!!結束時候仍然用黑色清空畫面
pygame.mouse.set_visible(True)
end_font = pygame.font.Font('MicrosoftYaqiHeiLight-2.ttf',48) # !!設定字體和字號
end_sur = score_font.render("你的分數是:{}/{}!".format(score,times_max), True, (255, 0, 0)) # !!生成計數表面
window.blit(sur, (0, 0))
window.blit(end_sur, (100, 100)) # 增加分數表面
else:
sur.blit(map, (0, 0)) #!!添加背景圖片
# 每幀循環執行的代碼
if tick > tick_max: # 每50次刷新變換一次
times=times+1 #增加計次
score_sur = score_font.render(
"分數:{}/{}!".format(score,times), False, (255, 0, 0)) # 重新生成分數文字表面
a = random.randint(0, 4) # 隨機0到4
pos = posAll[a] # 更新外部記錄的圓的位置
tick = 0 # 重置計數器
else: # 不刷新變換的時候
tick = tick+1 # 增加計數器
# 繪制鼠標
pygame.draw.circle(sur, clr, pos, 50) # 使用隨機位置畫地鼠
pygame.draw.circle(sur, (255, 0, 0), mpos, 10) # !在鼠標位置畫紅色圓
# 刷新畫面
window.blit(sur, (0, 0))
window.blit(score_sur, (200, 10)) # 增加分數表面
pygame.display.flip() #刷新畫面
注意我們先把圖片讀取,然后在每幀里面決定是否使用。運行后如下圖:
使用動態圖片
地鼠和錘子各有兩個狀態,正常的地鼠和被擊打的地鼠,正常的錘子和砸下的錘子,如下圖所示(下圖無法直接使用,請從網盤下載):
我們可以先把四個圖片都load
讀取進來成為rat1,rat2,ham1,ham2
,然后我們使用ratsur
和hamsur
表示真正要使用的表面,當鼠標按下的時候我們設定hamsur=ham2
是砸下圖片,當鼠標點擊位置距離地鼠小於地鼠半徑的時候我們使用ratsur=rat2
被砸中的圖片。最后我們再分別把地鼠和錘頭blit
到sur
上面。
改造后的代碼如下:
import pygame
import sys
import random
from pygame.locals import * # 引入鼠標事件類型
import time
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
sur = pygame.Surface([600, 400]) # 繪制背景容器
clr = (0, 0, 255)
posAll = [[100, 150], [300, 150], [500, 150], [
200, 300], [400, 300]] # 六個位置
rad = 50
tick = 0 # 計數器
pos = posAll[0] # 外面記錄圓的位置
# 分數
score = 0 # 分數計數
pygame.font.init() # 初始化文字
score_font = pygame.font.Font('MicrosoftYaqiHeiLight-2.ttf', 30) # !!設定字體和字號
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成計數表面
# 鼠標
pygame.mouse.set_visible(False) # !!隱藏鼠標
mpos = [300, 200] # !!記錄鼠標位置
times = 0 # 地鼠跳出的次數
times_max=10 #最多次數
tick_max=30 #地鼠每次跳多少幀
map=pygame.image.load('dds-map.jpg')#!!讀取圖片
rat1=pygame.image.load('rat1.png')#!!讀取地鼠圖片
rat2=pygame.image.load('rat2.png')#!!讀取被砸地鼠圖片
ham1=pygame.image.load('hammer1.png')#!!讀取錘子圖片
ham2=pygame.image.load('hammer2.png')#!!讀取砸下錘子圖片
while 1:
hamsur=ham1
ratsur=rat1
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠標按下事件
hamsur=ham2 #!!使用下落錘子
mpos = pygame.mouse.get_pos() # 獲取鼠標位置
dis = pygame.math.Vector2(
mpos[0]-pos[0], mpos[1]-pos[1]) # 計算坐標差
len = pygame.math.Vector2.length(dis) # 計算距離
if len < rad:
tick = 1000 # 立即變換位置
score = score+1 # 計分增加
ratsur=rat2 #!!使用被砸地鼠
elif event.type == MOUSEMOTION: # 當鼠標移動的時候
mpos = pygame.mouse.get_pos() # 更新鼠標位置
if times >= times_max:
# 顯示結束畫面
sur.fill((0, 0, 0)) #結束時候仍然用黑色清空畫面
pygame.mouse.set_visible(True)
end_font = pygame.font.Font('MicrosoftYaqiHeiLight-2.ttf',48) # !!設定字體和字號
end_sur = score_font.render("你的分數是:{}/{}!".format(score,times_max), True, (255, 0, 0)) # !!生成計數表面
window.blit(sur, (0, 0))
window.blit(end_sur, (100, 100)) # 增加分數表面
else:
sur.blit(map, (0, 0)) #添加背景圖片
# 每幀循環執行的代碼
if tick > tick_max: # 每50次刷新變換一次
times=times+1 #增加計次
score_sur = score_font.render(
"分數:{}/{}!".format(score,times), False, (255, 0, 0)) # 重新生成分數文字表面
a = random.randint(0, 4) # 隨機0到4
pos = posAll[a] # 更新外部記錄的圓的位置
tick = 0 # 重置計數器
else: # 不刷新變換的時候
tick = tick+1 # 增加計數器
sur.blit(ratsur,(pos[0]-50,pos[1]-70)) #繪制地鼠
sur.blit(hamsur,(mpos[0]-50,mpos[1]-100)) #繪制錘頭
# 刷新畫面
window.blit(sur, (0, 0))
window.blit(score_sur, (200, 10)) # 增加分數表面
pygame.display.flip() #刷新畫面
time.sleep(0.04) #!!保持畫面一點時間
注意這里的import time
和time.sleep(0.04)
這是讓每一幀停留一點點時間,0.04秒,每秒25幀(假設每幀畫圖不需要時間的話)。
另外我們再blit
的時候使用了(pos[0]-50,pos[1]-50)
這樣的偏移,因為圖片總是用左上角作為位置的起點,這樣偏移之后就變到了圖片中心,實際上我們又故意讓地鼠和錘子更高一些,就使用了(pos[0]-50,pos[1]-70)
。
運行之后的樣子如下圖:
讓游戲重新開始
每次顯示最終成績之后,能不能讓游戲3秒后重新開始呢?
我們設定一個gameover=0
,游戲結束后每幀都增加這個數字,如果gameover>100
,就是過了100幀,那么我們就重新開始。
重新開始必須意味着各種數據(分數,計時什么的)和畫面都要重置到原來的狀態。
修改后的整體代碼如下:
import pygame
import sys
import random
from pygame.locals import * # 引入鼠標事件類型
import time
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
sur = pygame.Surface([600, 400]) # 繪制背景容器
clr = (0, 0, 255)
posAll = [[100, 150], [300, 150], [500, 150], [200, 300], [400, 300]] # 六個位置
rad = 50
tick = 0 # 計數器
pos = posAll[0] # 外面記錄圓的位置
# 分數
score = 0 # 分數計數
pygame.font.init() # 初始化文字
score_font = pygame.font.Font("MicrosoftYaqiHeiLight-2.ttf", 30) # !!設定字體和字號
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成計數表面
# 鼠標
pygame.mouse.set_visible(False) # !!隱藏鼠標
mpos = [300, 200] # !!記錄鼠標位置
times = 0 # 地鼠跳出的次數
times_max = 10 # 最多次數
tick_max = 30 # 地鼠每次跳多少幀
map = pygame.image.load("dds-map.jpg") # !!讀取圖片
rat1 = pygame.image.load("rat1.png") # !!讀取地鼠圖片
rat2 = pygame.image.load("rat2.png") # !!讀取被砸地鼠圖片
ham1 = pygame.image.load("hammer1.png") # !!讀取錘子圖片
ham2 = pygame.image.load("hammer2.png") # !!讀取砸下錘子圖片
gameover = 0 #!!結束計時
gameover_max = 100 #!!結束計時最大值,超過這個值就重新開始
while 1:
hamsur = ham1
ratsur = rat1
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠標按下事件
hamsur = ham2 # !!使用下落錘子
mpos = pygame.mouse.get_pos() # 獲取鼠標位置
dis = pygame.math.Vector2(mpos[0] - pos[0], mpos[1] - pos[1]) # 計算坐標差
len = pygame.math.Vector2.length(dis) # 計算距離
if len < rad:
tick = 1000 # 立即變換位置
score = score + 1 # 計分增加
ratsur = rat2 # !!使用被砸地鼠
elif event.type == MOUSEMOTION: # 當鼠標移動的時候
mpos = pygame.mouse.get_pos() # 更新鼠標位置
if times >= times_max:
# 顯示結束畫面
sur.fill((0, 0, 0)) # 結束時候仍然用黑色清空畫面
pygame.mouse.set_visible(True)
end_font = pygame.font.Font("MicrosoftYaqiHeiLight-2.ttf", 48) # !!設定字體和字號
end_sur = score_font.render(
"你的分數是:{}/{}!".format(score, times_max), True, (255, 0, 0)
) # !!生成計數表面
sur.blit(end_sur, (100, 150))
cd = int((gameover_max - gameover) / 10)
cd_sur = score_font.render(
"重新開始倒計時{}".format(cd), True, (255, 0, 0)
) # !!生成計數表面
sur.blit(cd_sur, (100, 200)) # 增加分數表面
gameover = gameover + 1 #!!增加結束計時
else:
sur.blit(map, (0, 0)) # 添加背景圖片
score_sur = score_font.render(
"分數:{}/{}!".format(score, times + 1), False, (255, 0, 0)
) # 重新生成分數文字表面
sur.blit(score_sur, (200, 10)) # 增加分數表面
if tick > tick_max: # 每50次刷新變換一次
times = times + 1 # 增加計次
a = random.randint(0, 4) # 隨機0到4
pos = posAll[a] # 更新外部記錄的圓的位置
tick = 0 # 重置計數器
else: # 不刷新變換的時候
tick = tick + 1 # 增加計數器
if tick > 5: # 開始幾幀不顯示地鼠
sur.blit(ratsur, (pos[0] - 50, pos[1] - 70)) # 繪制地鼠
sur.blit(hamsur, (mpos[0] - 50, mpos[1] - 100)) # 繪制錘頭
# 刷新畫面
window.blit(sur, (0, 0))
pygame.display.flip() # 刷新畫面
time.sleep(0.04) # !!保持畫面一點時間
# !!重置游戲
if gameover > gameover_max:
pygame.mouse.set_visible(False)
times = 0
score = 0
gameover = 0
運行這個代碼就能反復玩游戲了。
到這里游戲看上去好了很多,但是還沒有背景音樂,打地鼠的時候也沒有音效,下一節我們繼續添加聲音。
添加音效
游戲里面的聲音分為兩種,一種叫音樂music,另一種叫音效sound。背景音樂是music,游戲里面的擊打聲點擊聲都是音效。同一時間播放的音樂一般只有一個,但音效可以有很多個同時播放。
pygame可以使用pygame.mixer.music.load('bg.mp3')
來載入foo.mp3音樂,然后pygame.mixer.music.play(0)
就可以播放,這里0表示播放1次,如果要無限次的播放則要改為-1.
但是如果要播放音效sound,那么pygame里面只能使用wav格式(並且不支持32位深,只支持16位深)。載入音效的方法是sd=pygame.mixer.Sound("hit.wav")
,播放是sd.play(0)
,這里0也是1次,一般音效不需要連續播放。
我們在游戲一開始就可以播放背景音樂了,但只有在點擊鼠標event.type == MOUSEBUTTONDOWN
的時候才播放錘子的聲音,只有在擊中地鼠的時候才播放地鼠的叫聲。
修改之后的代碼如下:
import pygame
import sys
import random
from pygame.locals import * # 引入鼠標事件類型
import time
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
sur = pygame.Surface([600, 400]) # 繪制背景容器
clr = (0, 0, 255)
posAll = [[100, 150], [300, 150], [500, 150], [200, 300], [400, 300]] # 六個位置
rad = 50
tick = 0 # 計數器
pos = posAll[0] # 外面記錄圓的位置
# 分數
score = 0 # 分數計數
pygame.font.init() # 初始化文字
score_font = pygame.font.Font("MicrosoftYaqiHeiLight-2.ttf", 30) # !!設定字體和字號
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成計數表面
# 鼠標
pygame.mouse.set_visible(False) # !!隱藏鼠標
mpos = [300, 200] # !!記錄鼠標位置
times = 0 # 地鼠跳出的次數
times_max = 10 # 最多次數
tick_max = 30 # 地鼠每次跳多少幀
map = pygame.image.load("dds-map.jpg") # !!讀取圖片
rat1 = pygame.image.load("rat1.png") # !!讀取地鼠圖片
rat2 = pygame.image.load("rat2.png") # !!讀取被砸地鼠圖片
ham1 = pygame.image.load("hammer1.png") # !!讀取錘子圖片
ham2 = pygame.image.load("hammer2.png") # !!讀取砸下錘子圖片
gameover = 0 # !!結束計時
gameover_max = 100 # !!結束計時最大值,超過這個值就重新開始
# 音樂和音效
pygame.mixer.music.load("bg.mp3") # !!載入背景音樂
pygame.mixer.music.play(-1) # !!無限播放背景音樂
hitsound = pygame.mixer.Sound("hit.wav") # !!載入擊打聲音
hurtsound = pygame.mixer.Sound("aiyo2.wav") # !!載入地鼠叫聲
while 1:
hamsur = ham1
ratsur = rat1
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠標按下事件
hamsur = ham2 # 使用下落錘子
hitsound.play() # !!播放擊打聲音
mpos = pygame.mouse.get_pos() # 獲取鼠標位置
dis = pygame.math.Vector2(mpos[0] - pos[0], mpos[1] - pos[1]) # 計算坐標差
len = pygame.math.Vector2.length(dis) # 計算距離
if len < rad:
tick = 1000 # 立即變換位置
score = score + 1 # 計分增加
ratsur = rat2 # 使用被砸地鼠
hurtsound.play() # !!播放地鼠聲音
elif event.type == MOUSEMOTION: # 當鼠標移動的時候
mpos = pygame.mouse.get_pos() # 更新鼠標位置
if times >= times_max:
# 顯示結束畫面
sur.fill((0, 0, 0)) # 結束時候仍然用黑色清空畫面
pygame.mouse.set_visible(True)
end_font = pygame.font.Font("MicrosoftYaqiHeiLight-2.ttf", 48) # 設定字體和字號
end_sur = score_font.render(
"你的分數是:{}/{}!".format(score, times_max), True, (255, 0, 0)
) # 生成計數表面
sur.blit(end_sur, (100, 150))
cd = int((gameover_max - gameover) / 10)
cd_sur = score_font.render(
"重新開始倒計時{}".format(cd), True, (255, 0, 0)
) # 生成計數表面
sur.blit(cd_sur, (100, 200)) # 增加分數表面
gameover = gameover + 1 # !!增加結束計時
else:
sur.blit(map, (0, 0)) # 添加背景圖片
score_sur = score_font.render(
"分數:{}/{}!".format(score, times + 1), False, (255, 0, 0)
) # 重新生成分數文字表面
sur.blit(score_sur, (200, 10)) # 增加分數表面
if tick > tick_max: # 每50次刷新變換一次
times = times + 1 # 增加計次
a = random.randint(0, 4) # 隨機0到4
pos = posAll[a] # 更新外部記錄的圓的位置
tick = 0 # 重置計數器
else: # 不刷新變換的時候
tick = tick + 1 # 增加計數器
if tick > 5: # 開始幾幀不顯示地鼠
sur.blit(ratsur, (pos[0] - 50, pos[1] - 70)) # 繪制地鼠
sur.blit(hamsur, (mpos[0] - 50, mpos[1] - 100)) # 繪制錘頭
# 刷新畫面
window.blit(sur, (0, 0))
pygame.display.flip() # 刷新畫面
time.sleep(0.04) # 保持畫面一點時間
# 重置游戲
if gameover > gameover_max:
pygame.mouse.set_visible(False)
times = 0
score = 0
gameover = 0
運行上面的代碼,可以聽到歡快的背景音樂,點擊鼠標時候會有捶地聲音,打中地鼠會有哎呦的叫聲。
發布軟件
我們寫的代碼目前只能在自己的電腦上運行,因為我們先要安裝python,然后還要安裝pygame才行,這和我們平常下載的軟件不同,下載的軟件可以直接運行(或者安裝自身后運行)。
Python給我們提供了自動把代碼打包成軟件的工具,Windows下推薦使用auto-py-to-exe工具。同樣先安裝pip install auto-py-to-exe
,然后只要執行auto-py-to-exe
就會打開一個窗口。
基本設置如下:
注意幾個地方:
- Script Location要指向你的主要.py文件,這里是
main.py
- Onefile選One Directory,這會把生產的所有文件放在一個文件夾中
- Console Window選Console Based,因為我們的pygame是基於控制台的
- Icon圖標,你可以在網上下載
.ico
文件,比如easyicon有很多,網盤里面有一個地鼠圖標icon.ico
- Additional Files附加文件,點擊Add Files按鈕要把全部用到的字體、圖片、聲音都選擇
- CONVERT .PY TO .EXE點擊這個按鈕進行生成,生成后會變為兩個藍色按鈕
點擊OPEN OUTPUT FOLDER打開生產的軟件目錄(默認在你的代碼文件夾下面的output文件夾內),找到那個和你的Script Location同名的文件,點擊它就可以運行游戲了。
也可以把這個MAIN.exe復制然后在桌面上粘貼快捷方式,以后只要點這個快捷方式就可以了。
在網盤文件中包含一個main.rar文件,下載它然后解壓就可以得到我打包生成的軟件了。
關於Mac蘋果電腦下面生成軟件的方法暫時遇到一點麻煩,搞定之后再更新,敬請關注。
第一個小游戲似乎開發完成了,但是還有很多內容,我們的代碼也有很多不合理的地方,下一篇我們一起來回顧和整理,並且繼續介紹更多小游戲的開發方法。
添加音效
游戲里面的聲音分為兩種,一種叫音樂music,另一種叫音效sound。背景音樂是music,游戲里面的擊打聲點擊聲都是音效。同一時間播放的音樂一般只有一個,但音效可以有很多個同時播放。
pygame可以使用pygame.mixer.music.load('bg.mp3')
來載入foo.mp3音樂,然后pygame.mixer.music.play(0)
就可以播放,這里0表示播放1次,如果要無限次的播放則要改為-1.
但是如果要播放音效sound,那么pygame里面只能使用wav格式(並且不支持32位深,只支持16位深)。載入音效的方法是sd=pygame.mixer.Sound("hit.wav")
,播放是sd.play(0)
,這里0也是1次,一般音效不需要連續播放。
我們在游戲一開始就可以播放背景音樂了,但只有在點擊鼠標event.type == MOUSEBUTTONDOWN
的時候才播放錘子的聲音,只有在擊中地鼠的時候才播放地鼠的叫聲。
修改之后的代碼如下:
import pygame
import sys
import random
from pygame.locals import * # 引入鼠標事件類型
import time
pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 設定窗口
sur = pygame.Surface([600, 400]) # 繪制背景容器
clr = (0, 0, 255)
posAll = [[100, 150], [300, 150], [500, 150], [200, 300], [400, 300]] # 六個位置
rad = 50
tick = 0 # 計數器
pos = posAll[0] # 外面記錄圓的位置
# 分數
score = 0 # 分數計數
pygame.font.init() # 初始化文字
score_font = pygame.font.Font("MicrosoftYaqiHeiLight-2.ttf", 30) # !!設定字體和字號
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成計數表面
# 鼠標
pygame.mouse.set_visible(False) # !!隱藏鼠標
mpos = [300, 200] # !!記錄鼠標位置
times = 0 # 地鼠跳出的次數
times_max = 10 # 最多次數
tick_max = 30 # 地鼠每次跳多少幀
map = pygame.image.load("dds-map.jpg") # !!讀取圖片
rat1 = pygame.image.load("rat1.png") # !!讀取地鼠圖片
rat2 = pygame.image.load("rat2.png") # !!讀取被砸地鼠圖片
ham1 = pygame.image.load("hammer1.png") # !!讀取錘子圖片
ham2 = pygame.image.load("hammer2.png") # !!讀取砸下錘子圖片
gameover = 0 # !!結束計時
gameover_max = 100 # !!結束計時最大值,超過這個值就重新開始
# 音樂和音效
pygame.mixer.music.load("bg.mp3") # !!載入背景音樂
pygame.mixer.music.play(-1) # !!無限播放背景音樂
hitsound = pygame.mixer.Sound("hit.wav") # !!載入擊打聲音
hurtsound = pygame.mixer.Sound("aiyo2.wav") # !!載入地鼠叫聲
while 1:
hamsur = ham1
ratsur = rat1
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠標按下事件
hamsur = ham2 # 使用下落錘子
hitsound.play() # !!播放擊打聲音
mpos = pygame.mouse.get_pos() # 獲取鼠標位置
dis = pygame.math.Vector2(mpos[0] - pos[0], mpos[1] - pos[1]) # 計算坐標差
len = pygame.math.Vector2.length(dis) # 計算距離
if len < rad:
tick = 1000 # 立即變換位置
score = score + 1 # 計分增加
ratsur = rat2 # 使用被砸地鼠
hurtsound.play() # !!播放地鼠聲音
elif event.type == MOUSEMOTION: # 當鼠標移動的時候
mpos = pygame.mouse.get_pos() # 更新鼠標位置
if times >= times_max:
# 顯示結束畫面
sur.fill((0, 0, 0)) # 結束時候仍然用黑色清空畫面
pygame.mouse.set_visible(True)
end_font = pygame.font.Font("MicrosoftYaqiHeiLight-2.ttf", 48) # 設定字體和字號
end_sur = score_font.render(
"你的分數是:{}/{}!".format(score, times_max), True, (255, 0, 0)
) # 生成計數表面
sur.blit(end_sur, (100, 150))
cd = int((gameover_max - gameover) / 10)
cd_sur = score_font.render(
"重新開始倒計時{}".format(cd), True, (255, 0, 0)
) # 生成計數表面
sur.blit(cd_sur, (100, 200)) # 增加分數表面
gameover = gameover + 1 # !!增加結束計時
else:
sur.blit(map, (0, 0)) # 添加背景圖片
score_sur = score_font.render(
"分數:{}/{}!".format(score, times + 1), False, (255, 0, 0)
) # 重新生成分數文字表面
sur.blit(score_sur, (200, 10)) # 增加分數表面
if tick > tick_max: # 每50次刷新變換一次
times = times + 1 # 增加計次
a = random.randint(0, 4) # 隨機0到4
pos = posAll[a] # 更新外部記錄的圓的位置
tick = 0 # 重置計數器
else: # 不刷新變換的時候
tick = tick + 1 # 增加計數器
if tick > 5: # 開始幾幀不顯示地鼠
sur.blit(ratsur, (pos[0] - 50, pos[1] - 70)) # 繪制地鼠
sur.blit(hamsur, (mpos[0] - 50, mpos[1] - 100)) # 繪制錘頭
# 刷新畫面
window.blit(sur, (0, 0))
pygame.display.flip() # 刷新畫面
time.sleep(0.04) # 保持畫面一點時間
# 重置游戲
if gameover > gameover_max:
pygame.mouse.set_visible(False)
times = 0
score = 0
gameover = 0
運行上面的代碼,可以聽到歡快的背景音樂,點擊鼠標時候會有捶地聲音,打中地鼠會有哎呦的叫聲。