讀古今文學網 > 父與子的編程之旅:與小卡特一起學Python > 24.6 電子寵物 >

24.6 電子寵物

我們將要建立一個簡化了的電子寵物程序,正如前面所說的一樣,這是一種仿真。你可以購買電子寵物玩具(比如有一個小屏幕的鑰匙鏈),下載電子寵物軟件,還有一些網站(如 Neopets 和 Webkinz),就採用了電子寵物的形式。當然,所有這些也都是仿真。它們會模仿一些真實動物的行為,會餓,會感到孤單,會覺得累。要讓它們快樂健康,你必須給它們餵食,和它們玩,還要帶它們看病。

我們的電子寵物會簡單得多,與你購買或在線玩的電子寵物相比沒有那麼真實,因為我只是想讓你有一些基本認識,而且我不希望代碼太過複雜。不過你可以在這個簡化版本的基礎上,根據你的想法進行擴展或改進。

我們的程序要具備以下特性。

  • 對這個寵物可以有 4 種活動:給它餵食、帶它散步、和它玩或者帶它看病。

  • 可以監測這個寵物的 3 種統計信息:飢餓感、快樂度和健康度。

  • 寵物可以醒著或者睡覺。

  • 飢餓感會隨時間增加。可以通過餵食減少飢餓感。

  • 寵物睡覺時飢餓感的增加會減慢。

  • 如果寵物在睡覺,你做任何活動都會讓它醒過來。

  • 如果寵物太餓了,它的快樂度會減少。

  • 如果寵物實在太餓了,它的健康度會減少。

  • 帶寵物散步會同時增加它的快樂度和健康度。

  • 與寵物玩會讓它的快樂度增加。

  • 帶寵物看病會讓它的健康度增加。

  • 寵物有 6 個不同的圖片:

    • 一個睡覺的圖片;

    • 一個醒著但什麼也不做的圖片;

    • 一個散步的圖片;

    • 一個玩耍的圖片;

    • 一個進食的圖片;

    • 一個看病的圖片。

圖片可以使用一些簡單的動畫。後面幾節我們將看到如何把所有這些整合在一起構成一個程序。

GUI

卡特和我為我們的電子寵物程序創建了一個 PyQt GUI。其中有一些按鈕(實際上是工具條上的圖標)用來完成活動,還有一些進度條顯示重要的統計信息。另外還留有一個位置顯示寵物的圖片(寵物正在做什麼)。

注意,窗口的標題欄上寫著 Virtual Pet(虛擬寵物)。怎麼設置窗口標題呢?在 Qt Designer 應用中新建一個窗口,然後在對像檢查器中點擊 MainWindow 對象。之後,在屬性編輯器中找到 windowTitle 屬性,將它改為 Virtual Pet(或者你想在標題欄中顯示的任意文字)。

用來控制寵物活動的一組按鈕是 PyQt 中一種叫做工具欄(Toolbar)的組件。工具欄和菜單欄一樣也有行為,但不同之處在於,工具欄中的每個行為都有一個與之關聯的圖標。

要添加一個工具欄,右鍵點擊主窗口,然後選擇 Add Toolbar(添加工具欄)。這會在窗口頂部創建一個非常小的工具欄。在對像檢查器中找到工具欄,點擊它。然後在屬性編輯器中找到 minimumSize 屬性,將它的寬設為 100,高設為 50。

要將行為(圖標)添加到工具欄上,點擊 Qt Designer 右下角的 Action Editor(行為編輯器)標籤。在 Action Editor 面板中任意位置點擊右鍵,然後選擇 New(新建)。你會看到一個用來添加新行為的對話框。你唯一需要輸入的是 Text,Qt Designer 會自動填寫對像名稱。然後在中間找到三個點(...)的小按鈕,點擊右邊的向下箭頭,選擇 Choose File,接著選擇你想在工具欄按鈕上使用的圖片文件。

要在工具欄中添加新圖標還有最後一步要做。一旦你創建了新的行為,就能在 Action Editor 的列表中看到它。現在你需要將它拖到工具欄上。當你拖過來時,你為新行為選擇的圖像將會作為工具欄的新圖標出現。Qt Designer 會自動縮放圖片以適應工具欄的大小。

血量是名為 Progress Bar(進度條)的組件類型。主圖像是一個 Push Button(我們之前用過),通過設置它的屬性,可以讓它看起來不像普通的按鈕,而是顯示一幅圖像。

窗口中其餘部分的文本是 Label 組件。

你可以像這樣使用 PyQt Designer 創建一個 GUI。你也可以(從示例文件夾中)將我們創建好的 GUI 加載到 Qt Desinger 中,以檢查這些組件和它們的屬性。

算法

要為電子寵物程序寫代碼,需要更明確地瞭解寵物的行為。以下是我們要使用的算法。

  • 我們把寵物的一「天」分為 60 個部分,每一部分稱為一個「滴答」。每個滴答的實際時間是 5 秒鐘,所以寵物的「一天」就是我們實際時間的 5 分鐘。

  • 寵物在 48 個滴答中都醒著,然後它想睡 12 個滴答。你可以把它叫醒,不過這樣會讓它很不高興!

  • 飢餓感、快樂度和健康度的範圍都是 0 到 8。

  • 醒著時,飢餓感每個滴答會增加 1 個單位,快樂度每 2 個滴答減少 1 個單位(除非在散步或者玩)。

  • 睡覺時,飢餓感每 3 個滴答增加 1 個單位。

  • 進食時,飢餓感每個滴答減少 2 個單位。

  • 玩時,快樂度每個滴答增加 1 個單位。

  • 散步時,快樂度和健康度每 2 個滴答增加 1 個單位。

  • 看病時,健康度每個滴答增加 1 個單位。

  • 如果飢餓感達到 7,健康度每 2 個滴答減少 1 個單位。

  • 如果飢餓感達到 8,健康度每個滴答減少 1 個單位。

  • 如果睡覺時被叫醒,快樂度減少 4 個單位。

  • 如果程序不在運行,寵物可能醒著(什麼也不做),也可能在睡覺。

  • 程序重啟時,我們會統計過去了多少滴答,並對應過去的每個滴答更新統計信息。

看起來好像規則很多,不過編寫代碼其實很容易。實際上,你可能還想增加更多的行為,讓它更加有趣。稍後就會給出代碼(還會做一些解釋)。

簡單動畫

並不總是需要 Pygame 才能完成動畫。我們可以在 PyQt 中通過使用定時器完成簡單的動畫。定時器每隔一段時間會創建一個事件。可以編寫一個事件處理器,在定時器到時間時讓某個事情發生。這就類似於為一個用戶動作編寫事件處理器,比如說點擊一個按鈕,只不過定時器事件是由程序(而不是用戶)生成的。定時器到時間時生成的事件類型是 timeout 事件。

我們的電子寵物 GUI 將使用兩個定時器:一個用於動畫,另一個用於滴答。動畫每半秒(0.5 秒)更新一次,滴答每 5 秒發生一次。

動畫定時器時間到時,我們會所顯示寵物的圖像。每個活動(進食、玩等)都有自己的一組圖像來實現動畫,每組圖像將存儲在一個列表中。動畫會循環顯示這個列表中的所有圖像。程序將根據正在進行的活動來確定使用哪個列表。

試一試,再試一試

這個程序中還要使用一個新內容,這稱為 try-except 塊。

如果程序要做一件事情,而且這個事情有可能導致錯誤,那麼最好提供一種辦法來收集錯誤消息並進行處理,而不是讓程序直接停止。這可以利用 try-except 塊來做到。

例如,如果想打開一個文件,但是這個文件並不存在,你就會得到一條錯誤消息。如果你沒有處理這個錯誤,程序會在這裡停止。不過,也許你想讓用戶重新輸入文件名(沒準她只是敲錯了)。利用 try-except 塊,你可以獲取到錯誤信息並繼續執行。

對於打開文件的例子,try-except 塊如下所示:

try:    file = open(\"somefile.txt\", \"r\")except:    print \"Couldn\'t open the file.  Do you want to reenter the filename?\"  

你想嘗試的部分(可能導致一個錯誤)要放在 try 塊中。在這個例子中就是嘗試打開一個文件。如果可以打開文件而不會導致錯誤,就會跳過 except 部分。

如果 try 塊中的代碼確實導致一個錯誤,就會運行 except 塊中的代碼。except 塊中的代碼告訴程序一旦出現錯誤該做些什麼。你可以這樣來考慮:

try:    做這件事 ( 不做其他事情……)except:    如果有錯誤,就做這件事  

try-except 語句是 Python 處理錯誤所採用的方法,這通常稱為錯誤處理(error handling)。錯誤處理允許你編寫可能出錯的代碼(甚至是很嚴重的錯誤,倘若沒有錯誤處理,這些錯誤在正常情況下甚至會讓你的程序停止),使程序仍能繼續運行。我們不打算在這本書裡更詳細地討論錯誤處理,不過我希望你能瞭解一些基礎知識,因為在電子寵物代碼中就會看到錯誤處理。

下面來看這個代碼,見代碼清單 24-4。這裡的說明已經對大部分工作做了解釋。這個代碼有點長,所以如果你不想自己鍵入,可以在 ExamplesVirtualPet 文件夾找到這個程序(如果你運行了本書的安裝程序)。也可以從這本書的網站(www.helloworldbook2.com)下載。PyQt UI 文件和所有圖片也都已經提供。試著運行這個程序,然後再看代碼,確保你能理解它是如何工作的。

代碼清單 24-4 VirtualPet.py

sleep_test 函數使用了 PyQt 的「警告信息」對話框。一系列的參數告訴它要顯示哪些按鈕,以及哪個是默認按鈕。代碼清單 24-4 中的註釋解釋了這一點。當對話框彈出來時(你試圖叫醒你的寵物時),看起來是這樣的:

即使你不能完全讀懂這個代碼也不用擔心。如果你希望學習更多有關 PyQt 的內容,可以先看看 PyQt 網站:www.riverbankcomputing.co.uk/software/pyqt/into。

在本章中,我們只是稍稍瞭解了計算機仿真的一點皮毛,知道了模擬真實世界中一些方面的基本思想,比如重力和時間。實際上,計算機仿真在科學、工程、醫藥、金融和很多其他領域都得到了廣泛使用。其中很多仿真非常複雜,即使用最快的計算機運行也需要花費幾天甚至幾個星期。不過鑰匙鏈上的小電子寵物也是一種仿真,有時最簡單的仿真也是最有意思的。

你學到了什麼

在這一章,你學到了以下內容。

  • 什麼是計算機仿真,為什麼使用計算機仿真。

  • 如何模擬重力、加速度和作用力。

  • 如何跟蹤和模擬時間。

  • 如何使用 pickle 將時間戳保存到文件。

  • 關於錯誤處理的一點知識(try-except)。

  • 如何使用定時器生成週期性的事件。

測試題

1. 列出使用計算機仿真的 3 個原因。

2. 列出你見過或知道的 3 種計算機仿真。

3. 使用哪種對像來存儲兩個日期或時間之差?

動手試一試

1. 為 Lunar Lander 程序增加一個「脫離軌道」測試。如果飛船飛出了窗口頂邊,而且速度超過 +100m/s,就停止程序,並顯示一條消息,比如「You have escaped the moon\'s gravity. No landing today!」(你已經脫離月球重力,無法著陸!)

2. 為 Lunar Lander 用戶增加一個選項,可以在飛船著陸後繼續玩這個遊戲,而不必重啟程序。

3. 為電子寵物 GUI 增加一個 Pause 按鈕。這會讓寵物的時間停止,不論程序是否在運行。(提示:這說明可能需要在 pickle 文件中保存「暫停」狀態。)