注:
想慢慢學習的同學可以看我的 《python 入門到游戲實戰專欄》(更新中)
想學 C 的同學可以看《大話系列之C語言》(基本更新完)
想學 C++ 的同學可以看《大話C++》(更新中)
想做習題的可以看《大學生C語言作業、習題100例白話詳解》
作者簡介
作者名:1_bit
簡介:CSDN博客專家,2020年博客之星TOP5,藍橋簽約作者。15-16年曾在網上直播,帶領一批程序小白走上程序員之路。歡迎各位小白加我咨詢我相關信息,迷茫的你會找到答案。系列教程將會在流量降低時轉為付費位置,流量多時將不會,各位抓緊時間學習喲~
學習開始
👸小媛:小 C,我想學做游戲了,有什么速成的辦法嗎? 😰
🐰小C:沒有,謝謝。
👸小媛:我看他們都可以,直接做一個飛機大戰,說是一下子就學會了。 😨
🐰小C:你是想先大概過一遍內容嗎?還是具體的全面的學?
👸小媛:我想先有一點體驗感,自己學的舒服玩一下也行。
🐰小C:那就可以,1小時搞定。
👸小媛:這么快?那剛剛你又說不行。 😣
🐰小C:你不是全面學,只學基礎核心就沒啥問題。一個小時搞定還是可以做點東西的。
👸小媛:那就趕緊開始吧。
🐰小C:那我們就學 python 吧,你覺得怎么樣?
👸小媛:可以呀,做出來游戲就可以了。
🐰小C:你電腦我記得有環境和編輯器,我們就用原本的就好了。
👸小媛:原本的是啥?
🐰小C:那個 vscode,我們用的庫是 pygame。
👸小媛:唔,懂了。
01 hello world
🐰小C:那我們就從頭開始學吧,首先打開我們的 vscode 創建一個文件叫做 game.py 進行代碼的測試吧。
👸小媛:了解,我已經新建好了。
🐰小C:那我們首先寫一個 hello world 吧。
👸小媛:hello world 是什么? 😰
🐰小C:是一個經典的計算機程序,就是程序運行的時候會顯示 hello world。
👸小媛:懂了,那怎么做呢?
🐰小C:首先你要知道,編程其實就是使用不同的“魔法指令”在計算機中創造不同的東西,python 用來顯示內容的指令就是 print()
,你用 print()
要顯示什么字符串就在里面加上去就可以了。
👸小媛:這樣嗎?
print(helloworld)
🐰小C:在這里需要跟你提一點,在 python 中字符串是需要使用雙引號引起來的。
👸小媛:懂了,你的意思是這樣。
print("helloworld")
🐰小C:對的,這個時候我們點擊運行按鍵就可以看到結果了。
👸小媛:出現結果了,在這里。
02 變量
🐰小C:那我們繼續往下講。我們接下來學一個容器,用來存儲值。
👸小媛:存值的內容有什么意義嗎?
🐰小C:有呀,你想想在游戲之中其實你的血量都是存在一個容器之中,還有你的昵稱,不然你覺得沒有東西存那這東西怎么顯示?
👸小媛:哈哈哈,之前不懂,現在懂了。 😂
🐰小C:變量也是超級簡單,我們直接給變量起個名字,用個等于號就可以存值了。你現在創建一個變量你想起什么名字呢?
👸小媛:那就起一個名字叫做 a 就好了。
🐰小C:那你想在這個變量 a 里面存什么值呢?
👸小媛:那就存一個 10 吧。
🐰小C:那么代碼就可以這樣寫。
a=10
👸小媛:就這樣? 😂
🐰小C:是的,我們創建一個變量直接一個名字,在這個變量名右邊用一個等于號連接一個值,那么這個值就會存儲到這個變量中。
👸小媛:真簡單。 😎
🐰小C:那你知道怎么存儲一個字符串嗎?
👸小媛:知道呀,就這樣。
a="1_bit"
🐰小C:為什么要這樣寫呢?
👸小媛:因為 a 是一個變量名,用一個等于號就可以把等于號右邊的值存到左邊的變量中,然后最開始你說在 python 中字符串是需要雙引號標記,那就是這樣寫咯。
🐰小C:不錯,理解透徹,那我們開始顯示變量里面所存儲的內容吧。
👸小媛:這個就不會了,怎么顯示呢?
🐰小C:很簡單,也是使用 print(),直接在 print() 的括號內填寫變量名就可以了。
👸小媛:這樣嗎?
a="1_bit"
print(a)
🐰小C:是的。
👸小媛:結果出來了。
🐰小C:使用 print() 可以顯示很多的內容,例如你想用字符串連接在一起顯示可以使用逗號進行分隔,首先我們創建多個變量。
a="1_bit"
b="2_bit"
c="3_bit"
👸小媛:這樣就可以創建幾個變量了嗎? 😲
🐰小C:是的,python 的代碼是一行行的從上往下書寫,這個切記。每一句結束后就需要換到下一行去進行編寫。
👸小媛:懂了。
🐰小C:那我們同時顯示這幾個變量的內容直接使用 print() 就可以了。在 print() 元你括號內填入幾個變量使用逗號進行隔開就行。
a="1_bit"
b="2_bit"
c="3_bit"
print(a,b,c)
👸小媛:我運行后顯示出來了。
🐰小C:你還可以在 print() 中填入其他的字符串當作值進行輸出顯示。
👸小媛:那意思就是說使用引號把字符串引起來就可以了吧?然后使用逗號隔開?
🐰小C:是的,這樣字符串也是值,只要填入就可以輸出顯示。
👸小媛:代碼是這樣,我運行出來了。
a="1_bit"
b="2_bit"
c="3_bit"
print("分別輸出 a b c 的值:",a,b,c)
03 變量運算
🐰小C:其實我們的變量是可以進行相加減的,例如以下代碼和結果。
a=11
b=2
c=31
print(a+b)
print(a-b)
print(a*c)
👸小媛:明白了,跟日常生活中的一樣。
🐰小C:其實只是基礎運算大致相同,我們可以看看下面這個示例。
a="11"
b="2"
c="31"
print(a+b)
print(a+b)
print(a+c)
👸小媛:為什么會這樣呢?
🐰小C:因為兩個字符串之間做加法,這個加法指的是將兩個字符串進行連接,因為字符串和數字是兩個類型。帶雙引號的 11 是字符串的 11,而不是數字的 11,你得明白這一點。
👸小媛:哈哈哈,懂了。就是說數字也是字符,看不同形態下的表現。 😋
🐰小C:是的。
04 邏輯判斷
🐰小C:接下來我們可以看下邏輯判斷了,這個是非常重要的知識點。
👸小媛:是不是在游戲中用的很多?
🐰小C:邏輯判斷你要做啥其實都用的很多。
👸小媛:那我就認真學習。
🐰小C:其實邏輯判斷就像你登錄游戲時,需要判斷你的帳號密碼一樣,判斷帳號密碼是否正確,正確就登錄游戲,錯誤就退出游戲,就是這個意思。
👸小媛:懂了。
🐰小C:邏輯判斷在 python 中使用的是 if。我們可以把這個 if 當作是一句魔法,我們在需要邏輯判斷的時候就把這個打上就可以了。
👸小媛:明白,就跟念咒語一樣。 😂
🐰小C:是的。我們打上 if 后,在 if 后面加上一個條件,然后使用冒號結束,就像下面一樣。
a=11
if a==11:print("a是等于11")
👸小媛:嗯,首先你是創建一個變量 a 存儲 11 這個值,然后使用 if 語句給了一個條件,這個條件是 a==11,然后冒號結束。不過我想問一下,你在這里打了兩個等于號是不是你打錯了?
🐰小C:這個沒有。在 python 中是使用兩個等于號進行判斷左右兩邊是否相等,也就是判斷兩個等于號的坐標 a 是否等于右邊的 11。
👸小媛:明白了,那為什么下一句 print() 前面要空幾個格呢?
🐰小C:你想想,如果條件正確了,是不是就執行一句話,條件錯誤了就應該執行另外一條代碼?
👸小媛:是的。
🐰小C:其實在這里是如果這個條件正確,就執行冒號后的下一行 print("a是等于11")
。前面使用幾個空格的意思是將表示這條代碼屬于 if 這個判斷結構內,和其他代碼不是一個結構的東西,這樣只要條件錯誤就不會執行 if 結構內的了,如果你放在外面就會被執行了。
👸小媛:懂了,你意思這樣就可以標識是這個 if 結構內的東西了,是 if 這個結構內部的。
🐰小C:是的,運行后將會顯示結果。
👸小媛:我修改了 a 的值他就不會顯示出來了,啥也沒顯示。 😨
a=111
if a==11:print("a是等于11")
🐰小C:其實我們 if 語句內可以打很多代碼的,因為編程是靈活的,例如這個示例:
a=11
if a==11:print("a是等于11")print("a是等于11")print("a是等于11")print("a是等于11")print("a是等于11")
👸小媛:是不是都要空相同的空格呀?
🐰小C:是的,這樣才表示是同一個層級。如果你亂空空格會出錯的。
👸小媛:明白。
🐰小C:如果這個時候我們想知道判斷錯誤,我們可以添加一個 else 語句,這樣錯誤的話就是顯示 else 語句內部的代碼了。
a=111
if a==11:print("a是等于11")print("a是等于11")print("a是等于11")print("a是等于11")print("a是等于11")
else:print("判斷錯誤")print("判斷錯誤")print("判斷錯誤")
👸小媛:明白了,這個 else 語句一定要緊跟著在 if 語句結束后嗎?而且他是頂頭的沒有進行空格。
🐰小C:是的,因為 if 和 else 是同級,如果你也空格了那不就是在 if 語句判斷對后才能執行嗎?這樣永遠就不會執行 else 語句了,并且這樣寫也是錯誤的;else 還可以緊跟在 elif 后面,當我們多條件的時候就可以使用 elif 語句。
👸小媛:那就舉個例子吧。
🐰小C:那你看下面。
a=2
if a==11:print("a是等于11")print("a是等于11")print("a是等于11")print("a是等于11")print("a是等于11")
elif a==2:print("a是等于2")print("a是等于2")print("a是等于2")
elif a==3:print("a是等于3")print("a是等于3")print("a是等于3")
else:print("判斷錯誤")print("判斷錯誤")print("判斷錯誤")
👸小媛:elif 后面跟著的就是條件嗎?例如 a2 和 a3?
🐰小C:是的,當 if 條件判斷錯誤后會依次進行判斷,哪一個條件判斷正確就執行那個條件內的代碼,如果所有條件錯誤那么就執行 else 部分。
👸小媛:明白了,還有多少才能學完基礎? 😩
🐰小C:已經學完一半了,超級快的,哈哈哈。
👸小媛:好,請繼續。
🐰小C:其實 if 還可以進行嵌套,例如下面這個代碼。
a=2
b=3
if a==2:if b==3:print("完全符合要求")
else:print("第一項要求都沒符合耶")
👸小媛:嵌套的意思就是在 if 里面再有一個 if 嗎?
🐰小C:是的,但是里面的 if 也有層級,要表示是里面 if 內的代碼還是需要使用幾個空格間隔,依次往里縮。
👸小媛:明白了。
05 循環
🐰小C:接下來我們學習循環。當你想重復運行某一條或者某一段代碼時我們可以使用循環節省我們的代碼編寫時間,例如下面這段代碼。
i=0
while i<10:print("你好")i=i+1
👸小媛:你首先創建了一個變量 i,然后我就不懂了。
🐰小C:while 是一個循環,就跟你使用 if 一樣,使用 while 表示要開始循環了;while 之后的是一個條件,也就是滿足這個條件才會循環 while 循環內的代碼,這個條件使用冒號結束,是不是感覺 while 的形式跟 if 語句很像呢?
👸小媛:是的,感覺很相同,然后最后的兩個在前面空了幾個格,并且使用了相同的空格,是表示是 while 循環結構內的代碼吧?
🐰小C:是的,這個是就會執行循環,每次循環都會執行 print("你好")
和 i=i+1
。由于條件是 i<10
,i 每次循環都會加 1,第一次循環 i 是 0,第二次循環 i 是 1,然后依次類推肯定會超過 10的,這個時候就不循環了。下面就是結果。
👸小媛:明白了。循環也可以進行嵌套吧?
🐰小C:是的,不過我們暫時不用講,由于是速成,所以我們在之后的游戲制作之中再做講解。
👸小媛:好的。
06 列表
🐰小C:接下來我們講一個列表。我們在進行存儲值的時候使用變量是存儲一個值,那么我們使用列表就可以存儲多個值了。
a=[99,6,7,85,2,3]
print(a)
print(a[0])
print(a[4])
a[0]="你好"
print("修改后的值是:",a)
🐰小C:在這里這個 a 就是列表,然后使用一個等于號,將我們想要存儲的值放到一個中括號內,并且值與值之間使用逗號進行分隔,這個時候就可以創建一個列表了。
👸小媛:明白了,感覺挺簡單的。然后 print(a)
就是顯示這個列表的值了吧? 😢
🐰小C:是的,然后 print(a[0])
意思就是輸出這個 a 列表內的第一個元素。在列表中 0 就表示第一個元素 99,然后 1 就表示第二個元素 6,然后以此類推,我們在輸出的時候使用一個變量名,然后后面使用方括號,在方括號內寫上你想顯示第幾個元素就可以取到這個元素然后將值進行顯示輸出了。
👸小媛:懂了,然后 a[0]="你好"
的意思就是給這個位置重新賦值?
🐰小C:是的,這個時候我們可以看到最后輸出所有值的時候第一個元素的內容發生了改變。
07 列表與 for 循環
🐰小C:其實我們還可以使用一個循環使我們的列表一個個值進行顯示,這個循環叫做 for 循環。
👸小媛:循環還有內容沒學完嗎? 😰
🐰小C:是的,還有一個 for 循環沒進行學習,你看下面的代碼示例。
a=[99,6,7,85,2,3]
for v in a:print(v)
👸小媛:每一個值都一個個輸出顯示了。
🐰小C:是的,代碼 for v in a:
中的 for 表示開始使用 for 循環,接下來的 v in a 你可以理解成直接在這里創建一個變量 v,然后這個變量 v 進到 a 這個列表中一個個去取值,首先會取到最開始的值,然后每次循環就會跳到下一個值,這個時候我們就可以把這個值取出,使用 print() 就可以進行顯示了。
👸小媛:原來是這么回事,理解了。 😂
08 自定義函數
🐰小C:接下來我們開始編寫自定義的工具了,其實 print() 我們可以稱為函數,函數我們可以理解成一個工具或者說一個功能。我們需要用到這些功能的時候字節拿過來用就可以了,現在我們要編寫一個菜單功能,每次用到菜單就不用自己去寫那么多代碼,直接使用就可以。
👸小媛:那這樣我不是可以節省很多時間了?
🐰小C:是的,這個就叫做自定義函數,自己編寫一個函數。你可以看下面的代碼示例。
def menu():print("這是一個菜單你可以進行查看")print("1.進入系統")print("2.退出系統")print("3.刪除系統")print("4.退出帳號")print("5.關閉軟件")menu()
👸小媛:這個時候不會是上面的 print 直接顯示的內容嗎?
🐰小C:不會,我先解釋一下這個的意思吧。我們可以看到 def,def 表示你開始創建一個自定義函數,def 后就是一個函數名之后使用一個括號,這是定義函數的一種形式,之后的話我們使用冒號進行結束就可以了。
👸小媛:例如我想創建一個函數叫做 abc,那么是不是可以這樣寫。
def abc():
🐰小C:是的,然后在冒號下一行開始編寫這個函數的代碼就可以了,一樣的需要使用空格表示這個代碼是屬于這個函數內的內容。
👸小媛:明白了。
🐰小C:調用函數就是使用函數的意思,直接使用函數名加一對圓括號就可以使用,此時就等于運行了函數內的代碼,這個時候就顯示出了內容。
👸小媛:意思說如果不使用就不會起作用?
🐰小C:是的,是這個意思。
👸小媛:明白了。
🐰小C:其實函數還可以接受參數,就像你使用 print() 一樣需要往里面傳入數據才能顯示。你自己創建一個函數也可以接受一下參數,參數其實就像你生活中用電飯鍋做飯,需要有米才可以煮飯,這個米就是這個電飯鍋功能的參數。
👸小媛:懂了,那怎么做呢?
🐰小C:很簡單,在自定義函數的圓括號內創建變量,如果是多個就使用逗號進行間隔就可以了。
👸小媛:你的意思是說這樣? 😂
def abc(a,b):
🐰小C:是的,例如下面這個代碼。
def abc(a,b):print(a+b)abc(1,2)
👸小媛:這個時候 1 就等于存到 a 里面,然后 2 就等于存到了 b 里面是吧?
🐰小C:是的,如果你只想函數作為計算,不輸出,我們可以使用一個叫做 return 的進行值的返回。例如以下代碼。
def abc(a,b):return a+bc=abc(1,2)
print(c)
👸小媛:你的意思是 return 會把 a+b 的結果給返回出去?
🐰小C:是的,這個時候 c 就可以進行接收,abc(1,2) 計算后就等于了 3,最后輸出 c 的內容就可以看到等于 3 了。
👸小媛:明白了。
09 類和對象
🐰小C:我們接下來需要學習的是面向對象。
👸小媛:面向對象是什么呀?我沒有對象。 😨
🐰小C:其實面向對象不是說你要有對象,其實就是我們可以創建一個類型,這個類型實例化后就是對象。
👸小媛:不懂,好難。😭
🐰小C:其實不難的,你看下面的示例。
class human:name=""age=0def say(self):print("hello")def myInfo(self):print("myName:",self.name,"myAge:",self.age)
👸小媛:完全看不懂啊,好難。
🐰小C:我一個個解釋給你聽吧。在上面代碼中的 class 就是表示現在要創建一個類別,human 就是這個類別的名稱。
👸小媛:你的意思就是 class 是關鍵字,后面就是這個類型的名稱時候吧?
🐰小C:是的,在這個 human 類型中,有兩個屬性;一個屬性叫做 name,另外一個屬性叫做 age。
👸小媛:就跟正常變量一樣,一個 name 存儲的是空字符串,一個 age 存儲的是年齡。
🐰小C:是的,在這里 name 就用來存儲名稱,age 用來存儲年齡,接下來就由兩個方法,一個叫做 say 一個叫做 myInfo。
👸小媛:這兩個是自定義函數吧?那參數為什么是個 self 呢?
🐰小C:這個 self 我們可以理解成當前這個類型之中的意思,家長自定義函數的參數之中我們可以當做表示這個自定義函數是屬于這個類。
👸小媛:你的意思就是加了 self 才表示是當前這個類型的方法?
🐰小C:對的,規定是這樣做的。你可以看這句代碼 print("myName:",self.name,"myAge:",self.age)
,self就是表示當前這個類型,self.name 就表示是當前這個類型中的 name 這個變量,我們可以理解那個小數點為 “的” 的意思,self.name
就是當前類型中的 name 變量。
👸小媛:明白了。😂
🐰小C:我們接著看一下下面的使用方法。
class human:name=""age=0def say(self):print("hello")def myInfo(self):print("myName:",self.name,"myAge:",self.age)xiaoM=human()
xiaoM.say()
xiaoM.myInfo()
xiaoM.name="XiaoMing"
xiaoM.age=18
xiaoM.myInfo()
🐰小C:xiaoM=human()
就是創建一個 human 對象。例如我們人是一個類型,那么具體到一個人就是一個對象,現在 human 這個類型創建到了一個具體對象存儲在 xiaoM 這個變量之中。
👸小媛:唔,明白了,有了類型才能創建到一個具體的對象。
🐰小C:嗯,然后我們可以通過這個對象使用這個類型的方法,因為這個對象就屬于這個類型。例如 xiaoM.say()
就表示使用這個類型中的 say() 方法,然后 xiaoM.myInfo() 也是;當然我們也可以使用 xiaoM.name="XiaoMing"
去賦予這個對象中這個 name 屬性值,然后在使用 myinfo 進行輸出,這個時候值就改變了。
👸小媛:唔,全明白了,哈哈哈。 😎
10 開始做游戲 pygame
🐰小C:接下來我們開始編寫一個小游戲吧。
👸小媛:這么快?
🐰小C:是的,已經可以去寫了的。首先我們需要做的是準備工作,我們在命令窗口中使用 pip 命令安裝 pygame 這個游戲庫,你的電腦已經有 pygame 了,那我們就不需要這一步了。
pip install pygame
👸小媛:嗯。
🐰小C:接下來我們的第一步是將 pygame 引入。
import pygame
🐰小C:import 就像你的一只手,然后 pygame 就是一個工具名,連起來就是將這個工具拿過來用。
👸小媛:明白了。
🐰小C:接下來我們就需要進行初始化。初始化就像你玩游戲需要創建一個角色一樣,這就是初始化。
import pygamepygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("這是一個飛機游戲")
🐰小C:上面代碼中的第二條 init 就是初始化的意思。
👸小媛:那個小數點是不是就表示 pygame 中的 init 方法?直接使用就可以初始化? 😰
🐰小C:是的,pygame.display.set_mode((600,800))
這句代碼我們可以理解成 pygame 這個工具中有一個工具叫做 display,display 有一個g功能就是創建窗口,名叫 set_mode,我們在 set_mode 中傳入這個屏幕的寬高,并且使用括號括起來寬高就可以創建出一個屏幕了,其中 600 是寬 800 是高;之后創建了屏幕后將這個屏幕給予一個變量,之后就可以通過這個變量對這個屏幕進行操作。
👸小媛:簡單,理解起來容易。 😎
🐰小C:接下來那一句代碼 pygame.display.set_caption("這是一個飛機游戲")
,set_caption 是 display 的另外一個功能,可以設置標題,直接將字符串當作參數傳入 set_caption 就可以了。
👸小媛:懂了。
11 游戲主循環
🐰小C:接下來我們需要開始游戲主循環的內容,所有游戲都是通過一個循環去監聽你在游戲中做了什么事,這個時候我們可以使用 while 循環給予一個 True 做條件,True 就表示永遠條件正確。
👸小媛:你的意思就是需要創建一個循環還一直看玩家按了什么鍵做了什么事?
🐰小C:對的,你看下面代碼。
import pygamepygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("這是一個飛機游戲")while True:for event in pygame.event.get():if event.type==pygame.QUIT:exit()
🐰小C:在 while 循環內有一個 for 循環用來取游戲中發生的所有事件。pygame.event.get()
將會獲取到玩家做了所有的事情,通過 for 循環一個個去取,event 這個變量就分別每次取得這些內容,使用 if 判斷 event 的類型 type 如果是 pygame 游戲中的退出 QUIT 那么就執行 exit() 退出整個程序。
12 游戲素材添加
👸小媛:唔,那也可以檢測上下左右按鍵吧?這樣就可以實現移動了?
🐰小C:是的,不過現在我們需要往這個游戲里面添加背景和角色,這些都是圖片,我們可以通過加載圖片資源創建背景和主角對象,我們都可以稱這些元素為精靈。
👸小媛:精靈,好聽的名字。 😢
🐰小C:你看下面的代碼。
import pygamebg=pygame.image.load(r'E:\2dsrc\src\img\bg.png')
hero=pygame.image.load(r'E:\2dsrc\src\img\hero1.png')
enemy=pygame.image.load(r'E:\2dsrc\src\img\enemy1.png')
enemy_boom=pygame.image.load(r'E:\2dsrc\src\img\enemy1_down1.png')
bullet=pygame.image.load(r'E:\2dsrc\src\img\bullet1.png')heroX=250
heroY=680pygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("這是一個飛機游戲")while True:screen.blit(bg,(0,0))screen.blit(hero,(heroX,heroY))for event in pygame.event.get():if event.type==pygame.QUIT:exit()
🐰小C:上面的代碼 pygame.image.load 就表示使用 pygame 中的 image 工具的 load 功能,load 就是加載圖片的意思;在 load 方法中傳入圖片的路徑就可以了,我在這里分別加載了 5 個圖片,一個是背景圖、一個是主角圖、一個是敵人圖、一個是敵人被擊中后的爆炸圖、一個是子彈圖片。
👸小媛:我電腦上你是放在同樣的路徑下吧?
🐰小C:是的,如果沒有圖片可以私聊 bit 哥(博主 https://blog.csdn.net/A757291228),他會統一發的。
👸小媛:明白。
🐰小C:我們接著看 screen.blit(bg,(0,0))
代碼和 screen.blit(hero,(heroX,heroY))
代碼,這兩句代碼都是用 blit 方法,blit 方法 是 screen 的功能之一,也就是可以在屏幕中畫出我們加載的圖片;blit 的第一個參數是圖片參數,第二個參數是整個屏幕的 x 和 y 坐標,也就是從哪里開始畫;x 越大越靠右,y 越大越靠下。
👸小媛:那為什么我運行了代碼后是一片黑屏? 😭
🐰小C:那是因為我們需要刷新,每次循環完我們都需要刷新整個界面,否則是不會呈現畫完的效果的。你在 while 循環最后加一個代碼,pygame.display.update()
,就如下所示。
import pygamebg=pygame.image.load(r'E:\2dsrc\src\img\bg.png')
hero=pygame.image.load(r'E:\2dsrc\src\img\hero1.png')
enemy=pygame.image.load(r'E:\2dsrc\src\img\enemy1.png')
enemy_boom=pygame.image.load(r'E:\2dsrc\src\img\enemy1_down1.png')
bullet=pygame.image.load(r'E:\2dsrc\src\img\bullet1.png')heroX=250
heroY=680pygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("這是一個飛機游戲")while True:screen.blit(bg,(0,0))screen.blit(hero,(heroX,heroY))for event in pygame.event.get():if event.type==pygame.QUIT:exit()pygame.display.update()
👸小媛:出來了耶。
13 控制角色移動
🐰小C:那么接下來我們來控制這個飛機左右移動吧。
👸小媛:期待。
🐰小C:我們創建一個函數,用來檢測用戶是否按下了上下左右。
import pygamebg=pygame.image.load(r'E:\2dsrc\src\img\bg.png')
hero=pygame.image.load(r'E:\2dsrc\src\img\hero1.png')
enemy=pygame.image.load(r'E:\2dsrc\src\img\enemy1.png')
enemy_boom=pygame.image.load(r'E:\2dsrc\src\img\enemy1_down1.png')
bullet=pygame.image.load(r'E:\2dsrc\src\img\bullet1.png')heroX=250
heroY=680
stepX=0 #此部分新增
stepY=0 #此部分新增pygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("這是一個飛機游戲")def keydown_envent(event,stepX,stepY):#此部分新增if event.key == pygame.K_RIGHT:stepX=5elif event.key == pygame.K_LEFT:stepX=-5elif event.key == pygame.K_UP:stepY=-5elif event.key == pygame.K_DOWN:stepY=5return stepX,stepYwhile True:heroX=heroX+stepXheroY=heroY+stepYscreen.blit(bg,(0,0))screen.blit(hero,(heroX,heroY))for event in pygame.event.get():if event.type==pygame.QUIT:exit()if event.type==pygame.KEYDOWN:#此部分新增stepX,stepY=keydown_envent(event,stepX,stepY)pygame.display.update()
🐰小C:以上代碼我在新增部分添加了注釋,主要添加了一個 keydown_envent 方法用來檢測按下事件后的處理。我們可以看到在 for 循環事件遍歷中,使用 if event.type==pygame.KEYDOWN:
檢測用戶是否按下鍵,隨后我們通過這個事件傳入到 keydown_envent 方法中做處理,判斷用戶按下的是否是右鍵 K_RIGHT、左鍵 K_LEFT、上鍵 K_UP、下鍵 K_DOWN。如果是右鍵那么就增加下次繪制圖片的 x 坐標值,下鍵就增加 y 坐標值這樣依次類推,所以在 while 循環中就有了下面這個代碼。
heroX=heroX+stepX
heroY=heroY+stepY
👸小媛:感覺有點像那個在書上畫畫,r案后翻動頁碼每次看到圖都不一樣,畫上去的人物就可以動了。
14 增加敵機
🐰小C:是的,就是這個原理,我們接著添加敵人。
import pygame,randombg=pygame.image.load(r'E:\2dsrc\src\img\bg.png')
hero=pygame.image.load(r'E:\2dsrc\src\img\hero1.png')
enemy=pygame.image.load(r'E:\2dsrc\src\img\enemy1.png')
enemy_boom=pygame.image.load(r'E:\2dsrc\src\img\enemy1_down1.png')
bullet=pygame.image.load(r'E:\2dsrc\src\img\bullet1.png')heroX=250
heroY=680
stepX=0
stepY=0 enemy_speed=2#此部分新增
enemy_objs=[]#此部分新增pygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("這是一個飛機游戲")def keydown_envent(event,stepX,stepY):if event.key == pygame.K_RIGHT:stepX=5elif event.key == pygame.K_LEFT:stepX=-5elif event.key == pygame.K_UP:stepY=-5elif event.key == pygame.K_DOWN:stepY=5return stepX,stepYdef enemy_show(enemy_objs,startY=-40):#此部分新增if len(enemy_objs)<5:while len(enemy_objs)<5:enemy_X=random.randint(0,500)enemy_pos=[enemy_X,startY]screen.blit(enemy,enemy_pos)enemy_objs.append(enemy_pos)else:i=0for pos in enemy_objs:screen.blit(enemy,pos)enemy_objs[i]=[pos[0],pos[1]+enemy_speed]i=i+1return enemy_objswhile True:heroX=heroX+stepXheroY=heroY+stepYscreen.blit(bg,(0,0))screen.blit(hero,(heroX,heroY))enemy_objs=enemy_show(enemy_objs) #此部分新增for event in pygame.event.get():if event.type==pygame.QUIT:exit()if event.type==pygame.KEYDOWN:#此部分新增stepX,stepY=keydown_envent(event,stepX,stepY)pygame.display.update()
🐰小C:以上代碼中添加了一個 enemy_show 方法,enemy_show 方法傳入了一個 enemy_objs 列表用來記錄創建的敵人對象,enemy_show 方法接收兩個參數,還有一個是默認的 Y 坐標。在 enemy_show 中,如果敵機數量小于 5 個,那么就直接使用 while 循環進行創建,并且把創建對象的 X 和 Y 值存儲到 enemy_objs 列表中,之后我們只需要控制每個敵機的位置坐標就可以控制 敵機移動了。
if len(enemy_objs)<5:while len(enemy_objs)<5:enemy_X=random.randint(0,500)enemy_pos=[enemy_X,startY]screen.blit(enemy,enemy_pos)enemy_objs.append(enemy_pos)
👸小媛:你的意思是控制敵機移動只需要控制記錄出現的坐標點進行繪制,那么就等于敵機在移動? 😭
🐰小C:是的。如果已經創建了 5 個 敵機,n阿么只需要根據他們的位置坐標進行 y 軸坐標的增加就可以了,也就是 enemy_show 方法中 else 部分的內容。
def enemy_show(enemy_objs,startY=-40):#此部分新增if len(enemy_objs)<5:while len(enemy_objs)<5:enemy_X=random.randint(0,500)enemy_pos=[enemy_X,startY]screen.blit(enemy,enemy_pos)enemy_objs.append(enemy_pos)else:i=0for pos in enemy_objs:screen.blit(enemy,pos)enemy_objs[i]=[pos[0],pos[1]+enemy_speed]i=i+1return enemy_objs
👸小媛:唔,原來如此,那么 enemy_speed 加多少就表示速度了吧?我看你在前面定義這個值是 5。
🐰小C:是的。你可以運行代碼試一試。
👸小媛:敵機下來了呢,真棒。 😎
15 加子彈
🐰小C:我們現在開始添加子彈吧,其實子彈添加也很簡單,只需要知道我們這個主角的位置,然后使子彈在這個位置頭部繪制,繪制后每次刷新后的距離都 -10 這樣子彈就可以飛上去了呢。
👸小媛:是的,我感覺會寫了。 😎
🐰小C:我們接著看代碼吧,我們設置空格鍵就是子彈發射按鍵,這個時候我們在事件方法中添加空格事件的響應,然后繪制出一個子彈就可以了。
import pygame,randombg=pygame.image.load(r'E:\2dsrc\src\img\bg.png')
hero=pygame.image.load(r'E:\2dsrc\src\img\hero1.png')
enemy=pygame.image.load(r'E:\2dsrc\src\img\enemy1.png')
enemy_boom=pygame.image.load(r'E:\2dsrc\src\img\enemy1_down1.png')
bullet=pygame.image.load(r'E:\2dsrc\src\img\bullet1.png')heroX=250
heroY=680
stepX=0
stepY=0
bullets_pos=[]#此部分新增
enemy_speed=2
enemy_objs=[]pygame.init()
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("這是一個飛機游戲")def keydown_envent(event,stepX,stepY,hero_pos):bullet_pos=[]#此部分新增 if event.key == pygame.K_RIGHT:stepX=5elif event.key == pygame.K_LEFT:stepX=-5elif event.key == pygame.K_UP:stepY=-5elif event.key == pygame.K_DOWN:stepY=5elif event.key == pygame.K_SPACE:#此部分新增bullet_pos=[hero_pos[0],hero_pos[1]+10]return stepX,stepY,bullet_posdef enemy_show(enemy_objs,startY=-40):if len(enemy_objs)<5:while len(enemy_objs)<5:enemy_X=random.randint(0,500)enemy_pos=[enemy_X,startY]screen.blit(enemy,enemy_pos)enemy_objs.append(enemy_pos)else:i=0for pos in enemy_objs:screen.blit(enemy,pos)enemy_objs[i]=[pos[0],pos[1]+enemy_speed]i=i+1return enemy_objswhile True:bullet_pos_=[]#此部分新增heroX=heroX+stepXheroY=heroY+stepYscreen.blit(bg,(0,0))screen.blit(hero,(heroX,heroY))enemy_objs=enemy_show(enemy_objs) i=0for v in bullets_pos:#此部分新增 bullets_pos[i]=[v[0],v[1]-10]screen.blit(bullet,(bullets_pos[i][0]+45,bullets_pos[i][1]))distance_b=[bullets_pos[i][0]+45,bullets_pos[i][1]]i=i+1for event in pygame.event.get():if event.type==pygame.QUIT:exit()if event.type==pygame.KEYDOWN:#此部分新增stepX,stepY,bullet_pos_=keydown_envent(event,stepX,stepY,[heroX,heroY])if len(bullet_pos_)>0:bullets_pos.append(bullet_pos_)pygame.display.update()
🐰小C:我們在響應按鍵的方法中添加了響應空格的處理,我們將記錄當前主角所在的目標位置 bullet_pos=[hero_pos[0],hero_pos[1]+10]
,然后做為返回值返回,返回之后判斷 bullet_pos_ 接收值后長度是否大于 1,大于則表示已經按下空格,則記錄在 bullets_pos 列表中;之后使用循環遍歷每個子彈的位置,然后在 Y 軸上減去 一個值即可發射子彈。
i=0
for v in bullets_pos:#此部分新增 bullets_pos[i]=[v[0],v[1]-10]screen.blit(bullet,(bullets_pos[i][0]+45,bullets_pos[i][1]))distance_b=[bullets_pos[i][0]+45,bullets_pos[i][1]]i=i+1
👸小媛:那 +45 是啥意思呢?
🐰小C:因為我們的飛機會占據一定寬度,+45 是為了保持子彈在飛機頭位置中間進行發射。
👸小媛:明白了,我的子彈出來了。 😎
16 添加擊中摧毀
🐰小C:我們接下來開始添加擊中摧毀吧。擊中摧毀其實就是判斷子彈與敵機的距離,我們使用歐氏距離就可以了,編寫一個方法。
def distance(bx,by,ex,ey):a=bx-exb=by-eyreturn math.sqrt(a*a+b*b)
👸小媛:不懂怎么辦。
🐰小C:哈哈哈,這個問題不是本篇的內容,不懂公式的大家搜索一下就可以了,或者直接使用這個方法。
👸小媛:問題不大。
🐰小C:接著我們在子彈移動時添加距離計算,如果子彈移動后與敵機小于一定距離,那么就在敵機位置顯示出爆炸圖片就可以了。
i=0
for v in bullets_pos:bullets_pos[i]=[v[0],v[1]-10]screen.blit(bullet,(bullets_pos[i][0]+45,bullets_pos[i][1]))distance_b=[bullets_pos[i][0]+45,bullets_pos[i][1]]ei=0for ep in enemy_objs:#此部分新增 if distance(distance_b[0],distance_b[1],ep[0],ep[1])<60:screen.blit(enemy_boom,(ep[0],ep[1]))enemy_objs[ei]=[random.randint(0,500),-50]ei=ei+1i=i+1
🐰小C:其實就是移動后,我們去循環每一輛敵機的位置,如果距離達到了我們就在那個位置顯示爆炸圖片,并且更改這個位置到初始位置重新掉落。
👸小媛:哈哈哈,可以了。 😎
🐰小C:那我們這個就做完了,其他內容就不說了。
👸小媛:行嘞,多謝小C。
🐰小C:完整代碼如下(改動了一下的)。
import pygame,random,mathbg=pygame.image.load(r'E:\2dsrc\src\img\bg.png')
hero=pygame.image.load(r'E:\2dsrc\src\img\hero1.png')
enemy=pygame.image.load(r'E:\2dsrc\src\img\enemy1.png')
enemy_boom=pygame.image.load(r'E:\2dsrc\src\img\enemy1_down1.png')
bullet=pygame.image.load(r'E:\2dsrc\src\img\bullet1.png')pygame.init() #初始化
screen=pygame.display.set_mode((600,800))
pygame.display.set_caption("這是一個飛機游戲")heroX=250
heroY=680
stepX=0
stepY=0enemy_speed=2
enemy_objs=[]
enemy_objs1=[]
enemy_objs2=[]
enemy_objs3=[]
bullets_pos=[]
bullet_speed=[]def enemy_show(enemy_objs,startY=-40):if len(enemy_objs)<5:while len(enemy_objs)<5:enemy_X=random.randint(0,500)enemy_pos=[enemy_X,startY]screen.blit(enemy,enemy_pos)enemy_objs.append(enemy_pos)else:i=0for pos in enemy_objs:screen.blit(enemy,pos)enemy_objs[i]=[pos[0],pos[1]+enemy_speed]i=i+1return enemy_objsdef screen_border(X,Y):#左右屏幕if X<0:X=0elif X>500:X=500#上下屏幕if Y<0:Y=0elif Y>700:Y=700return X,Ydef distance(bx,by,ex,ey):a=bx-exb=by-eyreturn math.sqrt(a*a+b*b)def keydown_envent(event,stepX,stepY,hero_pos):bullet_pos=[]if event.key == pygame.K_RIGHT:stepX=5elif event.key == pygame.K_LEFT:stepX=-5elif event.key == pygame.K_UP:stepY=-5elif event.key == pygame.K_DOWN:stepY=5elif event.key == pygame.K_SPACE:bullet_pos=[hero_pos[0],hero_pos[1]+10]print('space:',bullet_pos)return stepX,stepY,bullet_poswhile True:bullet_pos_=[]heroX=heroX+stepXheroY=heroY+stepYheroX,heroY=screen_border(heroX,heroY)screen.blit(bg,(0,0))screen.blit(hero,(heroX,heroY)) enemy_objs=enemy_show(enemy_objs) #enemy_objs1=enemy_show(enemy_objs1,-300)#enemy_objs2=enemy_show(enemy_objs2,-600)#enemy_objs3=enemy_show(enemy_objs3,-900)print(bullets_pos)i=0for v in bullets_pos:bullets_pos[i]=[v[0],v[1]-10]screen.blit(bullet,(bullets_pos[i][0]+45,bullets_pos[i][1]))distance_b=[bullets_pos[i][0]+45,bullets_pos[i][1]]ei=0for ep in enemy_objs:if distance(distance_b[0],distance_b[1],ep[0],ep[1])<60:print('\n\n\n\n\n\n\n\n\n\n\n\n boom')screen.blit(enemy_boom,(ep[0],ep[1]))enemy_objs[ei]=[random.randint(0,500),-50]ei=ei+1i=i+1for event in pygame.event.get():if event.type==pygame.QUIT:exit()if event.type==pygame.KEYDOWN:stepX,stepY,bullet_pos_=keydown_envent(event,stepX,stepY,[heroX,heroY])if len(bullet_pos_)>0:bullets_pos.append(bullet_pos_)pygame.display.update()