




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
匯報人:WPS程序設計基礎第九章模塊與包目錄01模塊與包的本質(zhì)02庫的安裝與導入03Python生態(tài)系統(tǒng)之Pygame庫04小試牛刀05拓展實踐:使用模塊組織代碼.
理解模塊與包的概念。.深入理解import語句。.能使用模塊與包組織代碼。學習目標PART19.1模塊與包的本質(zhì)9.1模塊與包的本質(zhì)我們已經(jīng)知道函數(shù)是完成特定功能的一段程序,為代碼的復用帶來方便。如果編寫的多個函數(shù)具有相關(guān)性,組合起來可以解決更大的問題,如文件路徑的處理或時間的處理。那這些函數(shù)就可以被組織在一個代碼文件(以“.py”為擴展名)中,整個代碼文件可以被其他的程序復用,這個代碼文件就是一個模塊。因此Python的模塊沒有什么神秘的,其本質(zhì)就是一個代碼文件。代碼文件中會有變量、語句、函數(shù)或類等內(nèi)容。而這個代碼文件或者說模塊可以被其他程序?qū)?,重復使用,因此模塊的價值在于代碼復用。沒有復用價值的代碼文件雖然理論上也是一個模塊,但意義不大。9.1模塊與包的本質(zhì)如果函數(shù)或類比較多,組織在一個代碼文件中會過于沉重,則會被分散到多個代碼文件。這多個代碼文件又會被組織在文件夾下,只要在文件夾下添加一個名為__init__.py的文件(init前后各有兩個下畫線,只要存在該文件就行,文件可以沒有內(nèi)容),該文件夾就成為包。由此可見,所謂模塊、包,其實都是對代碼的合理組織,目的是讓程序結(jié)構(gòu)更清晰,更好地復用代碼。而之前一直提到的庫則是一種通俗的稱謂,它強調(diào)的是一組有關(guān)聯(lián)的、可以廣為其他程序使用的代碼文件集合。庫既可以是模塊也可以是包,這取決于庫的規(guī)模。例如,random庫就是一個random.py代碼文件,因此random庫是一個模塊。而xml庫的代碼則分散在多個文件夾下的多個代碼文件中,因此xml庫是一個包。事實上在很多Python資料中,模塊、包與庫等這些概念往往混用,不會特意區(qū)別。本書之前也沒有刻意區(qū)別這些術(shù)語。9.1模塊與包的本質(zhì)這么看來,在邏輯上一個Python程序可以由包、模塊、函數(shù)組成。包之下可以有子包或模塊,而模塊則是寫在同一個文件中的函數(shù)、類等的集合。在物理上,Python程序是一行行的代碼,這些代碼分散在一個個的文件中,這些文件又位于一個個的文件夾中,如圖9.1所示。圖9.1顯示的是xml庫的目錄結(jié)構(gòu)。從圖左側(cè)可知,xml庫下有dom、etree、parsers、sax等多個文件夾。圖左側(cè)選中了etree文件夾,右側(cè)可見有一個__init__.py文件。事實上這些文件夾下均有一個__init__.py文件,因此它們都是包。而etree包下還有多個Python代碼文件,它們都是模塊。每一個模塊中都有可被其他程序使用的函數(shù)、類等,如第4章解析XML格式數(shù)據(jù)用到的fromstring()函數(shù)就位于ElementTree.py模塊中。PART29.2庫的安裝與導入
9.2.1使用pip安裝第三方庫Python
中的庫通常分為以下幾類。(
1)內(nèi)置的。內(nèi)置庫通常是
Python
的核心模塊,隨著
Python解釋器一并安裝,因此不需要另外
安裝,可以直接導入使用。內(nèi)置庫又稱為
Python標準庫。(2)第三方的。經(jīng)過幾十年的發(fā)展,Python
擁有的庫非常多,不可能都與解釋器一并安裝。這
些庫經(jīng)過審核后可以被廣大
Python開發(fā)者使用,這種現(xiàn)成的但并未隨著解釋器內(nèi)置的庫被統(tǒng)稱為第
三方庫。使用它們時需要先安裝再導入。(3)自定義的。在大型系統(tǒng)的開發(fā)中,開發(fā)者往往將系統(tǒng)功能分為多個模塊來實現(xiàn),然后在主
模塊文件或其他代碼文件中導入使用其他功能的模塊。這些主要為自己的軟件程序服務的模塊就是
自定義的模塊。9.2.1使用pip安裝第三方庫內(nèi)置庫直接導入即可使用,但第三方庫是需要安裝的。Python
生態(tài)系統(tǒng)中有很多第三方庫具有
廣泛的應用領域,如
NumPy、SciPy
等在科學計算、數(shù)據(jù)分析、人工智能等很多領域都有廣泛的應
用。在第
5
章使用jieba庫時介紹了如何在
PyCharm
中安裝第三方庫,但安裝第三方庫未必要依賴
PyCharm編程工具,更通用的方式是使用pip工具。高版本的
Python解釋器在安裝過程中默認已經(jīng)
將pip
工具一并安裝了,所以可以直接在Windows
命令提示符窗口中使用pip
工具。下面以安裝
Pygame為例,演示如何使用pip安裝第三方庫。打開
Windows
的命令提示符窗口,在光標后輸入“pip”,然后直接按
Enter鍵即可看到關(guān)于pip
工具的使用幫助。如果是要安裝工具包,如
Pygame,則只需輸入“pipinstallpygame”命令,按
Enter
鍵后
pip會自動去網(wǎng)絡上下載指定的工具包并安裝,如圖
9.2所示。pip工具默認是去國外的站點上
下載,如果速度過慢則可以更換為國內(nèi)的鏡像服務器,這方面的信息可以去搜索引擎進行查詢。9.2.2導入模塊的不同形式庫只是一個形象的、通俗的稱謂,“導入庫”的真實含義是要復用該庫提供的某些代碼。而庫的代碼是位于模塊(代碼文件)中的,因此使用import語句導入庫時要指明導入的代碼文件,也就是模塊。1.導入整個模塊導入整個模塊是最基本的形式,即import<模塊名>。前面的例子中導入庫大多使用的是這種形式。以這種形式導入后,使用模塊中的函數(shù)、類等內(nèi)容時都要添加模塊名前綴。但由于庫的規(guī)模不同,有的庫本身只是一個模塊,如random庫、math庫等,導入就很簡單;有的庫有多個模塊,如xml庫。對于xml這類有多個模塊的庫,導入時不能簡單地書寫庫名,因為真正要導入的是模塊,所以必須說明要導入xml庫中的哪個模塊。一般這種情形下模塊都會位于包(文件夾)下,因此在導入模塊時必然涉及文件夾路徑。只是import語句中會將路徑分隔符改為點,于是就有下面代碼9.1的寫法,這也是在第4章出現(xiàn)過的寫法,現(xiàn)在應該理解得更清楚了。9.2.2導入模塊的不同形式代碼
9.1
導入整個模塊
9.2.2導入模塊的不同形式代碼
9.1
導入整個模塊
代碼中的random
模塊導入時直接書寫模塊對應的代碼文件名,注意不用寫文件的擴展名。而
xml庫的
ElementTree.py模塊在
xml\etree\文件夾下,因此導入時將路徑分隔符改為點,同樣不用寫
文件擴展名。當然,無論模塊文件所處的路徑深淺,這種將整個模塊導入的形式要求在使用模塊中
的函數(shù)等屬性時必須添加模塊前綴,所以
choice()函數(shù)及
fromstring()函數(shù)在使用時都必須有前綴名。
而
xml.etree.ElementTree作為前綴確實過長,書寫不便,所以
import語句可以使用
as關(guān)鍵字給導入
的模塊起別名,這樣只需寫
ET.fromstring()即可,較為方便。另外,程序要導入多個模塊時,理論上可以使用一個
import
語句,模塊名使用逗號分隔。但Python
不建議使用一行
import導入多個模塊,推薦使用多個
import語句,每行導入一個模塊。9.2.2導入模塊的不同形式代碼
9.1
導入整個模塊
2.導入模塊的某個屬性如果只是需要使用模塊中的一兩個屬性,不想將該模塊中的其他內(nèi)容都導入自己的代碼文件的作用域中,因為那樣可能會讓自己的程序變得臃腫。針對這種情形可以使用如代碼9.2所示的形式來直接導入目標屬性。相對于傳統(tǒng)的import形式,代碼9.2所示的形式是使用什么只導入什么,更有針對性。但如果要使用模塊中較多的屬性內(nèi)容,這種方式就不適合了。9.2.2導入模塊的不同形式代碼
9.1
導入整個模塊
代碼9.2導入模塊中的個別屬性fromrandomimportchoice#僅導入模塊中要使用的函數(shù)fromxml.etree.ElementTreeimportfromstringxml_str="""<data><entryauthor="孔子">學而時習之,不亦說乎?</entry><entryauthor="子夏">日知其所亡,月無忘其所能,可謂好學也已矣。</entry><entryauthor="顧炎武">有一日未死之身,則有一日未聞之道。</entry></data>"""root=fromstring(xml_str)#直接書寫函數(shù)名,沒有前綴data_base=[]forentryinroot:author=entry.attrib["author"]content=entry.textdata_base.append((author,content))entry_selected=choice(data_base)#沒有前綴print(entry_selected)9.2.2導入模塊的不同形式代碼
9.1
導入整個模塊
使用from直接導入模塊中的目標屬性后,使用它們時無須書寫模塊前綴。這一點既有優(yōu)點也有弊端。優(yōu)點是書寫簡潔、方便;弊端是在導入多個模塊時,因為沒有模塊前綴,所以不知道哪個函數(shù)來自哪個模塊,不同模塊的同名函數(shù)會發(fā)生名稱沖突,為程序引入了不必要的混亂因素。PART39.3Python生態(tài)系統(tǒng)之Pygame庫9.3Python生態(tài)系統(tǒng)之Pygame庫代碼
9.1
導入整個模塊
Pygame庫是Python生態(tài)系統(tǒng)中比較有名的用來開發(fā)游戲的庫,它提供了易用的、豐富的音頻、視頻操作功能,非常適合用來開發(fā)小型游戲。實際上,動手編寫游戲是一個非常好的學習編程的途徑,學習編寫游戲可能比玩游戲更有意思。9.3.1初識Pygame代碼
9.1
導入整個模塊
Pygame庫中有很多模塊,分別負責游戲開發(fā)中的各類任務。例如,pygame.display負責處理界面顯示方面的操作,pygame.time負責和時間有關(guān)的操作,pygame.mixer可以處理音頻。其中,pygame.display下的set_mode()函數(shù)用來創(chuàng)建游戲的主界面,這個函數(shù)會返回一個Surface對象,代表著游戲主界面。Surface對象有一個blit()方法,可以將游戲形象(Pygame稱為精靈)“繪制”在需要的位置。游戲一般有一些精心設計的游戲形象,Pygame將這些游戲形象稱為精靈(sprite)。精靈可能是任何東西,可以是拿著武器沖鋒陷陣的戰(zhàn)士,也可以是被動挨打的無生命的乒乓球,又或者是戰(zhàn)士手中的槍、用來打球的球拍等,這些都可以看成游戲形象,都可以被稱為精靈。游戲就是按照預設的邏輯讓這些精靈不斷變化,形成不同的游戲局面,讓玩家沉浸其中,得到樂趣。9.3.1初識Pygame代碼
9.1
導入整個模塊
游戲過程有兩面,一面是玩家看到的屏幕上五光十色的游戲角色在運動、動作、產(chǎn)生、消亡。這些精靈們有各自的外觀形象,它們在屏幕上的活動也是連續(xù)的,真的好像有生命一樣。但這一切都是假象,精靈的形象不過是一些圖片,精靈不同的狀態(tài)對應不同的圖片,這些圖片可以根據(jù)游戲需要出現(xiàn)在指定位置。游戲的另一面才是其真容:沒有動作,更不連續(xù),一切都是數(shù)據(jù)的變化。所有的精靈都只是一組數(shù)據(jù),數(shù)據(jù)的改變意味著精靈出現(xiàn)了某種變化。游戲只是記錄每個精靈下一刻的數(shù)據(jù)狀態(tài),然后根據(jù)這些數(shù)據(jù)將對應的精靈形象(圖片)在恰當?shù)臅r間“繪制”在屏幕恰當?shù)奈恢?。因為畫面更新速度非???,在人看來畫面是連續(xù)的。所以游戲開發(fā)除設計好各色精靈的外觀形象外,更重要的其實還是看不見的各種數(shù)據(jù)結(jié)構(gòu)的設計,使用什么樣的數(shù)據(jù)結(jié)構(gòu)記錄維護游戲精靈的狀態(tài),使用什么樣的算法去改變數(shù)據(jù)狀態(tài)是游戲內(nèi)在的靈魂。接下來通過一個簡單的小例子來練習使用Pygame開發(fā)游戲。9.3.2搭建游戲主框架代碼
9.1
導入整個模塊
游戲過程有兩面,一面是玩家看到的屏幕上五光十色的游戲角色在運動、動作、產(chǎn)生、消亡。這些精靈們有各自的外觀形象,它們在屏幕上的活動也是連續(xù)的,真的好像有生命一樣。但這一切都是假象,精靈的形象不過是一些圖片,精靈不同的狀態(tài)對應不同的圖片,這些圖片可以根據(jù)游戲需要出現(xiàn)在指定位置。游戲的另一面才是其真容:沒有動作,更不連續(xù),一切都是數(shù)據(jù)的變化。所有的精靈都只是一組數(shù)據(jù),數(shù)據(jù)的改變意味著精靈出現(xiàn)了某種變化。游戲只是記錄每個精靈下一刻的數(shù)據(jù)狀態(tài),然后根據(jù)這些數(shù)據(jù)將對應的精靈形象(圖片)在恰當?shù)臅r間“繪制”在屏幕恰當?shù)奈恢谩R驗楫嬅娓滤俣确浅?欤谌丝磥懋嬅媸沁B續(xù)的。所以游戲開發(fā)除設計好各色精靈的外觀形象外,更重要的其實還是看不見的各種數(shù)據(jù)結(jié)構(gòu)的設計,使用什么樣的數(shù)據(jù)結(jié)構(gòu)記錄維護游戲精靈的狀態(tài),使用什么樣的算法去改變數(shù)據(jù)狀態(tài)是游戲內(nèi)在的靈魂。接下來通過一個簡單的小例子來練習使用Pygame開發(fā)游戲。9.3.2搭建游戲主框架代碼
9.1
導入整個模塊
Pygame庫中有多個模塊,可根據(jù)需要導入所需的模塊。其中,pygame.locals模塊定義了Pygame中預置的常量,如標志窗體退出事件的常量QUIT。另外,在游戲窗體退出后,整個程序的運行也要終止,所以這里還需要用到sys庫中的exit()函數(shù),如代碼9.3所示。9.3.2搭建游戲主框架代碼
9.1
導入整個模塊
代碼9.3搭建游戲主框架importPygamefrompygame.localsimportQUITimportsyspygame.init()#初始化
Pygamesurface=pygame.display.set_mode((640,480))#游戲窗體大小pygame.display.set_caption('Hello,Pygame!')#窗體標題whileTrue:#主循環(huán)foreventinpygame.event.get():#獲取發(fā)生的事件ifevent.type==QUIT:#如果有退出事件pygame.quit()#Pygame退出sys.exit()#程序停止執(zhí)行pygame.display.update()#刷新畫面9.3.2搭建游戲主框架代碼
9.1
導入整個模塊
運行這段代碼可以看到一個指定尺寸的Pygame窗體,其標題欄為指定的文字內(nèi)容,單擊窗口右上角的“關(guān)閉”按鈕結(jié)束程序,如圖9.3所示。9.3.2搭建游戲主框架代碼
9.1
導入整個模塊
這段程序只是一個基本的框架,并沒有什么具體的游戲情節(jié),但還是有幾個重要的信息。首先是對Pygame各模塊進行初始化,然后在調(diào)用display模塊的set_mode()函數(shù)產(chǎn)生主窗體界面時可以指定窗口尺寸。如果長寬尺寸都為0,則產(chǎn)生一個和屏幕一樣大小的窗體。程序?qū)et_mode()函數(shù)返回的代表窗體界面的Surface對象保存在一個變量中,以便在游戲細節(jié)中使用。接下來調(diào)用了display.set_caption()函數(shù)設置窗體標題欄信息。這里并沒有指明要設置的是哪一個Surface窗口,因為Pygame同一時間只有一個Surface對象是當前窗口,因此無須說明。再往下就是重點了,這里有個條件為True的循環(huán),不妨稱其為游戲的主循環(huán)。程序運行后該循環(huán)會不停地執(zhí)行。游戲進行時需要不停地刷新畫面,因此完成游戲刷新的代碼應該寫在這個循環(huán)中。9.3.2搭建游戲主框架代碼
9.1
導入整個模塊
當然循環(huán)不能成為死循環(huán),打破這個循環(huán)的是玩家關(guān)閉窗口事件。事實上游戲進行中可能發(fā)生很多事件(event),如窗口關(guān)閉事件、單擊鼠標事件、鼠標指針移動事件、鍵盤上的按鍵事件等。每個事件都有一個編號,如退出事件的編號為256。但使用編號不友好,故Pygame為這些事件都定義了名稱;如退出事件記為QUIT,又因其值不變,故一般稱為常量。發(fā)生的事件會被送到一個事件隊列中。通過調(diào)用pygame.event.get()函數(shù)可以獲取當前事件隊列中的所有事件,代碼遍歷發(fā)生的事件,看看其中有沒有退出事件(QUIT),如果有則退出游戲。退出時首先要退出Pygame,然后調(diào)用sys.exit()退出Python系統(tǒng)。程序循環(huán)中的最后一句update()負責把緩存中的畫面數(shù)據(jù)真正送到屏幕上,不斷更新界面顯示。9.3.3完善游戲細節(jié)代碼
9.1
導入整個模塊
下面在游戲框架代碼的基礎上來真正做點什么,如讓一個卡通橘子臉在屏幕上不斷地變換兩種表情,而且還能跟隨方向鍵移動。要完成這個場景首先要預備好兩個橘子臉圖片,一個高興的表情,一個悲傷的表情。有了這樣兩個圖片,只需快速交替顯示它們就可以出現(xiàn)變臉的效果。而跟隨方向鍵移動時需要知道玩家按下了哪個鍵,并根據(jù)按鍵方向更新橘子臉的位置數(shù)據(jù),再根據(jù)最新位置數(shù)據(jù)在界面上重新繪制出橘子臉,這樣橘子臉就可以移動了。當然繪制前還要確認應該使用兩個表情中的哪一個。這就是整個代碼要完成的主要工作。接下來將對代碼的分析分成兩大部分,while主循環(huán)之前的預備工作,以及while主循環(huán)內(nèi)部要負責的工作。9.3.3完善游戲細節(jié)代碼
9.1
導入整個模塊
1.預備工作階段除設置游戲窗體的大小、標題等常規(guī)任務外,預備工作階段最重要的任務是將兩個不同表情的橘子臉圖片讀入內(nèi)存,使用pygame.image.load()函數(shù)完成這個工作。因為有兩個圖片,為了訪問方便,將兩個圖片載入后保存在一個列表中。load()函數(shù)載入圖片后返回的也是一個Surface對象。也就是說,不論是窗體界面,還是代表游戲精靈的圖片,在Pygame看來都是Surface對象。因為它們都是游戲外表的一層皮,真正的游戲精靈是由無形的、看不見的數(shù)據(jù)來表示的。因此接下來需要一個數(shù)據(jù)結(jié)構(gòu)來表示真正的橘子臉精靈,這里選擇了Pygame提供的Rect類。顧名思義,這個類可以表示一個矩形,而橘子臉精靈顯然可以概括為一個矩形,由兩部分共同組成,看不見的Rect對象和看得見的表情圖片。Rect對象保存了橘子臉精靈的狀態(tài)數(shù)據(jù),表情圖片出現(xiàn)在游戲窗體的什么位置完全由Rect對象的數(shù)據(jù)決定,表情圖片只是外在的一層皮。9.3.3完善游戲細節(jié)代碼
9.1
導入整個模塊
明白了大概任務,再來研讀預備工作的代碼就好理解了,細節(jié)如代碼9.4所示。與上一段游戲的大框架代碼相比,這里多導入了幾個locals模塊下的常量,如K_RIGHT等按鍵事件,主要用來實現(xiàn)橘子臉跟隨方向鍵移動。代碼9.4橘子臉游戲的預備階段importPygamefrompygame.localsimportQUIT,K_RIGHT,K_LEFT,K_UP,K_DOWNimportsys#預備工作pygame.init()WINDOW_WID,WINDOW_HEI=(640,480)surface=pygame.display.set_mode((WINDOW_WID,WINDOW_HEI))pygame.display.set_caption('Orangeface...')imgs=[]#保存橘子臉圖片的列表foriinrange(2):img=pygame.image.load('file\\Orange-'+str(i)+'.png')imgs.append(img)9.3.3完善游戲細節(jié)代碼
9.1
導入整個模塊
代碼9.4橘子臉游戲的預備階段img_rect=pygame.Rect(0,0,32,32)face_change_limit=2000face_change_step=3face_id=0move_speed=1background=(255,255,255)#代表橘子臉的數(shù)據(jù)結(jié)構(gòu)#當face_change_limit按照face_change_step#的速度減為0時橘子臉會變換表情#按鍵移動的速度#背景色9.3.3完善游戲細節(jié)代碼
9.1
導入整個模塊
在代碼文件所在位置的file文件夾下預備好兩個32像素×32像素的不同表情的圖片,為了方便,兩個圖片命名為Orange-0.png和Orange-1.png,這樣pygame.image.load()函數(shù)即可將它們載入。這兩個圖片被保存在imgs列表中,因此可以通過imgs[0]和imgs[1]訪問。有了橘子精靈的外在形象,還要有代表橘子精靈的內(nèi)在數(shù)據(jù)結(jié)構(gòu),因此通過Rect類定義一個矩形對象img_rect,它保存了矩形的左上角坐標及長寬共4項數(shù)據(jù)。img_rect對象會時刻記錄橘子精靈的位置,游戲一開始,橘子精靈出現(xiàn)在窗體的左上角,因此橫縱坐標都為0,長寬均為32像素,這是由圖片的尺寸決定的。后面在游戲的主循環(huán)結(jié)構(gòu)中會根據(jù)玩家按下不同的方向鍵來不斷更新img_rect的數(shù)據(jù),再根據(jù)img_rect不斷地繪制橘子精靈的外在圖片就可以實現(xiàn)移動效果了。9.3.3完善游戲細節(jié)代碼
9.1
導入整個模塊
再接下來的幾行代碼初看似乎不易理解,其實也是完成一些循環(huán)之前的必要數(shù)據(jù)準備工作。因為橘子精靈不僅可以跟隨方向鍵移動,還在不停地變化表情。這就要求定期地更換顯示的表情圖片,一會兒是imgs[0],一會兒是imgs[1]。那么多長時間更換表情呢?這由兩個變量face_change_limit與face_change_step共同決定,變量face_change_limit每次減少face_change_step,當face_change_limit小于等于0時,就意味著該更換表情圖片了。因此在face_change_limit值一定的情況下,face_change_step的值越大,換表情的頻率就越快。變量move_speed定義了橘子精靈的移動速度,其實就是每次根據(jù)按鍵移動位置時,img_rect對象的坐標改變多少。改變得越大,一次按鍵移動的距離就越大。代碼的最后按照RGB顏色模型給出白色,這個顏色將被設置為游戲窗體的背景色。所有這些預備的變量都會在游戲主循環(huán)中用到,所以接下來看看主循環(huán)內(nèi)是如何利用這些變量實現(xiàn)預期效果的。9.3.3完善游戲細節(jié)代碼
9.1
導入整個模塊
2.主循環(huán)階段游戲主循環(huán)的代碼實現(xiàn)如代碼9.5所示。在循環(huán)結(jié)構(gòu)中,首先通過surface.fill()方法將界面背景“填充”為指定顏色。每次循環(huán)都會執(zhí)行這行代碼,這意味著主窗口界面會不斷地被“填充”,之前界面上的畫面內(nèi)容就被白色覆蓋掉了,好比一面墻被重新粉刷,原來墻上的圖案就都不見了。因此橘子臉要重新繪制,每次繪制時都要判斷使用哪個表情圖片,是imgs[0]還是imgs[1]。這里就用到了face_change_limit與face_change_step兩個變量。face_change_limit每次循環(huán)會減少face_change_step,當face_change_limit由初始值2000降到小于等于0時,換表情的動作就該發(fā)生了。因此讓face_id加1,如果face_id原來是0,則現(xiàn)在為1;如果原來為1,則現(xiàn)在為2。之后將face_id除以2的余數(shù)賦給face_id本身??梢钥闯鼋?jīng)過這樣處理后,face_id的取值會在0和1之間交替變換,程序就是根據(jù)face_id去imgs列表中提取相應的表情的。因為對face_id值的處理并不是每次循環(huán)都發(fā)生,而是要face_change_limit從初始值減到0才發(fā)生一次。因此變量face_change_limit與face_change_step就控制了表情更替的速度,讀者可以在預備階段將face_change_step的值調(diào)大來試試效果。9.3.3完善游戲細節(jié)代碼
9.1
導入整個模塊
代碼9.5橘子臉游戲的主循環(huán)階段whileTrue:foreventinpygame.event.get():ifevent.type==QUIT:pygame.quit()sys.exit()surface.fill(background)#重填窗體背景face_change_limit-=face_change_stepifface_change_limit<=0:#換臉發(fā)生face_change_limit=2000face_id+=1face_id%=29.3.3完善游戲細節(jié)代碼
9.1
導入整個模塊
代碼9.5橘子臉游戲的主循環(huán)階段surface.blit(imgs[face_id],img_rect)#根據(jù)最新位置繪制橘子臉#根據(jù)按鍵移動橘子臉
keys=pygame.key.get_pressed()#獲取被按下的鍵ifkeys[K_RIGHT]:
img_rect.x+=move_speed
ifkeys[K_LEFT]:
img_rect.x-=move_speed
ifkeys[K_UP]:
img_rect.y-=move_speed
ifkeys[K_DOWN]:
img_rect.y+=move_speed
#防止橘子臉移出窗體9.3.3完善游戲細節(jié)代碼
9.1
導入整個模塊
代碼9.5橘子臉游戲的主循環(huán)階段ifimg_rect.x<0:img_rect.x=0ifimg_rect.x>WINDOW_WID-32:img_rect.x=WINDOW_WID-32ifimg_rect.y<0:img_rect.y=0ifimg_rect.y>WINDOW_HEI-32:img_rect.y=WINDOW_HEI-32pygame.display.update()9.3.3完善游戲細節(jié)代碼
9.1
導入整個模塊
決定了使用的表情圖片,接下來的工作就是將表情圖片繪制在img_rect指定的位置。這是通過主窗口對象的blit()方法完成的,這個方法可以將游戲精靈的外在形象貼在窗體的指定位置。而img_rect對象記錄的位置是可以隨玩家操作方向鍵而變化的,循環(huán)內(nèi)接下來的代碼就是實現(xiàn)這個工作的。Pygame的key模塊下的get_pressed()函數(shù)可以獲知玩家按下了什么鍵。在該函數(shù)的返回結(jié)果中查看4個方向鍵是否被按下,并相應更新img_rect對象左上角的坐標。例如,如果玩家按下了向右的方向鍵,則keys[K_RIGHT]為真,因此img_rect的橫坐標增大,增大多少由move_speed決定,所以move_speed控制橘子臉的移動速度。最后還有一個問題需要考慮,橘子臉不能移到游戲窗口之外,因此每輪循環(huán)都要判斷img_rect中橫縱坐標的上下限。到此程序的邏輯就都實現(xiàn)了,將代碼9.4與代碼9.5合在一起運行,調(diào)整預備階段的一些變量值,觀察橘子臉的移動速度、換臉頻率等效果,可以加深對代碼的理解。如圖9.4所示是代碼運行后的結(jié)果。9.3.3完善游戲細節(jié)代碼
9.1
導入整個模塊
決定了使用的表情圖片,接下來的工作就是將表情圖片繪制在img_rect指定的位置。這是通過主窗口對象的blit()方法完成的,這個方法可以將游戲精靈的外在形象貼在窗體的指定位置。而img_rect對象記錄的位置是可以隨玩家操作方向鍵而變化的,循環(huán)內(nèi)接下來的代碼就是實現(xiàn)這個工作的。Pygame的key模塊下的get_pressed()函數(shù)可以獲知玩家按下了什么鍵。在該函數(shù)的返回結(jié)果中查看4個方向鍵是否被按下,并相應更新img_rect對象左上角的坐標。例如,如果玩家按下了向右的方向鍵,則keys[K_RIGHT]為真,因此img_rect的橫坐標增大,增大多少由move_speed決定,所以move_speed控制橘子臉的移動速度。最后還有一個問題需要考慮,橘子臉不能移到游戲窗口之外,因此每輪循環(huán)都要判斷img_rect中橫縱坐標的上下限。到此程序的邏輯就都實現(xiàn)了,將代碼9.4與代碼9.5合在一起運行,調(diào)整預備階段的一些變量值,觀察橘子臉的移動速度、換臉頻率等效果,可以加深對代碼的理解。如圖9.4所示是代碼運行后的結(jié)果。PART49.4小試牛刀9.4小試牛刀前面介紹了使用Pygame開發(fā)小游戲的基本流程,接下來在小試牛刀環(huán)節(jié)開發(fā)一款可玩性更強的小游戲。游戲中有一個小球在窗口中“游蕩”,玩家通過左右移動鼠標指針控制一個擋板,任務是不讓小球掉落到窗口下沿。隨著玩家擊打小球次數(shù)的增多,小球的移動速度會越來越快,游戲難度越來越高。當小球掉落游戲結(jié)束時,窗口中顯示玩家的擊球次數(shù)。如果玩家愿意,則單擊開始新的一局。游戲運行的效果如圖9.5所示。9.4.1游戲預備工作游戲需要準備小球與擋板的圖片素材,這個例子中使用的小球圖片有8像素,擋板的寬度為55像素。游戲代碼假設這些圖片素材位于file文件夾下。整個程序仍然分為主循環(huán)之前的預備工作和while主循環(huán)兩部分,先來看預備工作階段,細節(jié)如代碼9.6所示。代碼被空行分成幾個小段落,后面會詳細解釋。(代碼見書213頁9.6)9.4.2游戲主循環(huán)所有預備工作做完后,接下來是在while循環(huán)中不斷更新的工作。這些工作構(gòu)成了代碼9.7,循環(huán)內(nèi)的代碼也被空行分成了幾個段落,下面進行逐一分析。(代碼見書215頁9.7)PART59.5拓展實踐:使用模塊組織代碼當程序稍具規(guī)模后,可以根據(jù)功能將代碼分布在多個文件中,每個代碼文件就是一個模塊。程序由多個模塊組成,必然會出現(xiàn)在某個模塊中導入其他自定義模塊的情形。接下來就以一個具體的例子演練如何使用模塊組織代碼。9.5拓展實踐:使用模塊組織代碼在人類的民主活動中投票是一個重要的形式。常用的投票形式往往是選民人手一票,每個人將自己的一票投給自己支持的候選人,獲得票數(shù)多的候選人勝出。除此以外有沒有其他的投票模式呢?1770年,法國舉辦了一場選舉,選舉規(guī)則是每一個選民擁有一張選票,并按對每位候選人的認可程度,在選票上給所有候選人進行排序。作為選票結(jié)果的統(tǒng)計者,數(shù)學家波達設想的方法是將選票上的位次轉(zhuǎn)換為分值,這樣可把每一張選票上的候選人排名名次轉(zhuǎn)換成一串相應的數(shù)字。例如,在有4個候選人的選舉中,排在第1名的候選人因為擊敗了3個人所以得3分。同理第2名得2分,第3名得1分,第4名得0分。然后把所有選票上每個候選人各自得到的分數(shù)全部加在一起,最后累計得分最高者獲勝。這種方法被命名為波達計數(shù)法(Bordacount)。9.5.1多樣的投票模式再來看看同一時期的另一位法國數(shù)學家孔多塞(Condorcet)提出的一種計票方式。每個候選人都要和其他候選人進行兩兩的對決。在兩人對決時,每一票都屬于排名靠前的候選人,最終獲得選票多的人在兩人對決中勝出。只有在兩兩對決的過程中戰(zhàn)勝所有其他候選人的才是最終獲勝者??锥嗳嬈狈梢赃x出被大多數(shù)人擁護的選舉人,但也有可能因為沒人能戰(zhàn)勝所有其他人,從而導致沒有獲勝者。9.5.1多樣的投票模式假設有4位候選人,名字分別為A、B、C、D。關(guān)于這場選舉的投票數(shù)據(jù)被保存在一個文本文件中,文件的每一行代表一個投票人的投票結(jié)果。這個結(jié)果是投票人對4位候選人的一個排位順序,使用空格分隔,如下(數(shù)據(jù)有刪減)。9.5.2一個具體的投票問題下面按照多數(shù)計票法、波達計票法和孔多塞計票法3種投票方式來對同一個投票問題進行處理,看看結(jié)果有何不同??梢钥闯觯瑹o論使用何種計票方法,整個計票的工作大致如下:首先,讀入投票數(shù)據(jù)。其次,匯總投票數(shù)據(jù)。根據(jù)不同計票方法,匯總過程不盡相同。例如,對于多數(shù)計票法,每個選民的投票只有排在第一順位的候選人有效,而波達計票法則要將每個選民的排位換算為相應的分數(shù)??锥嗳嬈狈▌t關(guān)注候選人兩兩對決的勝負。無論采用哪種計票方法,最后都要根據(jù)匯總結(jié)果,給出選舉結(jié)論。因此計票工作可以分成幾個函數(shù)來完成。(1)負責讀入投票數(shù)據(jù)的read_vote_data()函數(shù)。(2)按照不同計票方法進行匯總的幾個函數(shù)。(3)根據(jù)匯總結(jié)果給出選舉結(jié)論的give_vote_result()函數(shù)。這些函數(shù)可以被分在不同的模塊中,按照不同計票方式進行匯總的函數(shù)可以統(tǒng)一放在一個模塊中,這個模塊文件可以命名為vote_methods.py。而read_vote_data()函數(shù)和give_vote_result()函數(shù)可以放在同一個模塊中,可以命名為vote_tools.py。主程序則寫在第三個代碼文件中,這樣整個程序被分為3個模塊,主程序所在的模塊需要導入另外兩個模塊。為了演示方便,這里假設所有的代碼文件都在同一個目錄下。9.5.2一個具體的投票問題先來看vote_tools模塊。這個模塊下有兩個函數(shù),分別是讀入選舉數(shù)據(jù)的read_vote_data()函數(shù)和根據(jù)計票匯總結(jié)果給出選舉結(jié)論的give_vote_result()函數(shù)。read_vote_data()函數(shù)的細節(jié)如代碼9.8所示。這個函數(shù)需要知道保存投票數(shù)據(jù)的文件名,而其返回值則是一個嵌套的列表,該列表的每一個元素是原數(shù)據(jù)文件中的一行按照空格拆分后的列表。代碼9.8模塊vote_tools中負責讀取數(shù)據(jù)的函數(shù)defread_vote_data(vote_file):"""讀取投票數(shù)據(jù)的函數(shù)參數(shù)vote_file:文件名9.5.3模塊vote_tools代碼9.8模塊vote_tools中負責讀取數(shù)據(jù)的函數(shù)返回值:嵌套列表"""vote_data=[]withopen(vote_file,"r")asf:forlineinf:one_vote=line.split()#按空格拆分vote_data.append(one_vote)returnvote_data9.5.3模塊vote_toolsgive_vote_result()函數(shù)的細節(jié)如代碼9.9所示。這個函數(shù)需要拿到匯總的結(jié)果aggregate_dic,這是一個字典,記錄了每個候選人的得票情況,或者是得分,又或者是該候選人戰(zhàn)勝的對手數(shù)量。也就是說盡管有多種計票方式,但每種計票方式最后匯總的結(jié)果都是一個字典,該字典會傳遞給give_vote_result()函數(shù)。因為孔多塞計票法的規(guī)則導致其有可能沒有獲勝者,所以處理細節(jié)略有不同。give_vote_result()函數(shù)還有一個參數(shù),用來判斷當前使用的計票方式是否為孔多塞計票法,該參數(shù)的默認值為假。give_vote_result()函數(shù)的返回值有兩項,一項是記錄最終獲勝候選人的列表winner,另一項是這些勝者的得票或得分情況。如果是孔多塞計票法,則winner有可能為空。9.5.3模塊vote_tools代碼9.9模塊vote_tools中負責給出選舉結(jié)論的函數(shù)defgive_vote_result(aggregate_dic,condorcet=False):"""根據(jù)匯總結(jié)果,給出最終投票結(jié)論"""winner=[]ifcondorcet:highest_vote=len(aggregate_dic)–1#戰(zhàn)勝所有其他候選人forcandidateinaggregate_dic.keys():ifaggregate_dic[candidate]==highest_vote:winner.append(candidate)break9.5.3模塊vote_tools代碼9.9模塊vote_tools中負責給出選舉結(jié)論的函數(shù)else:highest_vote=0forcandidateinaggregate_dic:#出現(xiàn)一個候選人比之前所有人的票數(shù)都高ifaggregate_dic[candidate]>highest_vote:winner.clear()winner.append(candidate)highest_vote=aggregate_dic[candidate]elifaggregate_di
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 舞蹈上課協(xié)議書
- 廣場舞成員受傷協(xié)議書
- 煤礦合伙人合同協(xié)議書
- 英歐加班協(xié)議書
- 船舶贈予協(xié)議書
- 財產(chǎn)產(chǎn)權(quán)協(xié)議書
- 肇事雙方協(xié)議書
- 肱骨手術(shù)協(xié)議書
- 羊棚租賃協(xié)議書
- 配送租賃協(xié)議書
- 中文版自殺可能量表
- openstack云計算平臺搭建課件
- 勞務實名制及農(nóng)民工工資支付管理考核試題及答案
- 裝飾藝術(shù)運動課件
- 【審計工作底稿模板】FH應付利息
- 胃腸減壓技術(shù)操作流程.
- 工貿(mào)企業(yè)安全管理臺賬資料
- 三方協(xié)議書(消防)
- 工序能耗計算方法及等級指標
- 預激綜合征臨床心電圖的當前觀點
- 閥門檢修作業(yè)指導書講解
評論
0/150
提交評論