概述
個人比較喜歡玩這些答題類的游戲,在這類的游戲中其實存在着一些冷知識在里面。練習pygame的過程中,在網絡上搜索,幾乎沒有找到這類游戲的示例教程,就蒙生了制作一個答題游戲的念頭,最開始的時候,這個游戲是使用鍵盤輸入的方式來答題的,沒有開始界面,沒有結束界面,后來幾經修改,改為全鼠標操作。打包了exe文件,無需安裝python直接點擊exe文件也可以使用。
詳細
主要思路
游戲一般都有一個顯示名稱的title頁,還有一個關於游戲介紹的界面,以及主要的內容——答題的界面。還有游戲結束時的一些統計數據。預想中的游戲完整是還包含了題庫在線獲取,有統計榜等內容,但是由於自己沒有可以使用的公網地址和存儲,這個演示改為單機版。
准備工作
開發的過程中,只使用了pygame一個外部庫。其他的特性都是使用python自帶的。
本游戲使用到的圖片來自網絡,做了少量的處理。包括了一張圖片作為鼠標樣式,一張圖片作為開始界面的背景,一張圖片作為游戲過程的背景,一張圖片作為游戲結束時統計的背景。
收集一些題目,保存為xml文件,文件的結構如下圖:
為增加游戲的可玩性和驚喜度,題量盡量不要少於50題,這里我只是作為測試和演示,只收集了20題內容,基本上是python的基礎知識題。
需要自定義字體,否則將無法顯示中文,將字體文件保存在font文件夾中。
titleFont = pygame.font.Font('font/YaHei.ttf', 150)
globalFont = pygame.font.Font('font/Hei.ttf', 36)
questionFont = pygame.font.Font('font/HuaKanSong.ttf', 24)
answerFont = pygame.font.Font('font/HuaKanSong.ttf', 22)
helpFont = pygame.font.Font('font/HuaKanSong.ttf', 24)
實現過程的部分代碼展示
-
自定義鼠標樣式代碼,概念上就是先獲取鼠標的坐標,隱藏原來的鼠標樣式,重新定義鼠標的位置是圖片的什么位置,我是定義在圖片的左上角,然后將該圖片畫出。這樣的步驟就完成了自定義鼠標。
mouseCursor = pygame.image.load('img/cursor.png').convert_alpha()
載入鼠標的圖片時,記得需要轉換透明區域,圖片的保存也是需要保存為可以保留透明區域的圖片格式
x, y = pygame.mouse.get_pos() # 獲取鼠標的坐標 mouseCursor = pygame.image.load('img/cursor.png').convert_alpha() # 載入鼠標的圖片 pygame.mouse.set_visible(False) # 隱藏原來的鼠標樣式 x -= 0 y -= 0 SUBFACE.blit(mouseCursor, (x, y)) # 繪畫出鼠標樣式,並且定義鼠標的坐標
-
讀取題庫的實現,題目保存在一個xml文件中。使用內置的xml模塊讀取該文件,並解析出題目、答案、正確答案等信息。然后再隨機取出其中的10道題,形成本次開始游戲的題目。
assert os.path.exists(filename), '題庫文件: %s 不存在,游戲無法執行。' % (filename)
利用assert做斷言判斷,如果加載的題庫文件不存在,直接把游戲奔潰掉,因為如果沒有題庫這個就什么都玩不了了。
# 讀取xml文件中的題庫 question_data = parse(filename) # 得到根節點 root = question_data.documentElement game_level = [] questions = root.getElementsByTagName("question") for item in questions: q_list = {} answerList = [] question = item.getAttribute("title") answer_items = item.getElementsByTagName("answer") # 返回一個列表 answerList.append(answer_items[0].getElementsByTagName("a")[0].childNodes[0].data) answerList.append(answer_items[0].getElementsByTagName("b")[0].childNodes[0].data) answerList.append(answer_items[0].getElementsByTagName("c")[0].childNodes[0].data) answerList.append(answer_items[0].getElementsByTagName("d")[0].childNodes[0].data) correct = item.getElementsByTagName("correct")[0].childNodes[0].data q_list['question'] = question q_list['answers'] = answerList q_list['correct'] = correct game_level.append(q_list)
上面的代碼會將xml文件中的數據讀取出來后存放為一個列表,每一道題是一個字典,包括了題目、四個選擇答案、正確的答案三個部分,而選擇答案又是一個列表。
# 生產隨機指定數量的題集,利用set的去重特性,這樣當set的長度是10時,就是10個不重復的數字 tmp_level = set() while len(tmp_level) < 10: randNum = random.randint(0, len(game_level) - 1) tmp_level.add(randNum) new_question = [] for i in tmp_level: new_question.append(game_level[i]) # 因為set的緣故,提取出來的題目是按順序排列的,需要打亂一次,形成每次游戲時的題目順序的獨特隨機性 random.shuffle(new_question) return new_question
最后是隨機生成指定數量的一組數字,用於獲取隨機的問題集,由於set()是有序的,在獲取了新的隨機問題集完成后,還需要再將這個問題集打亂。這樣做的目的可以讓每次開始游戲時,都存在隨機性,就算兩次隨機選擇出來的題目一樣,也會因為再次隨機打亂而顯示不同。
整個讀取文件的函數,是這個游戲的重要部分,其他的內容無非就是界面的顯示而已。 -
答題控制的邏輯,先獲取鼠標的當前位置,當鼠標在答案的方形范圍內,就先將答案改變顏色,提示玩家當前選中備選的是已經改變顏色的答案。點擊該答案后,就判斷和該題的正確答案是否一致,一致返回yes錯誤返回no,這兩個返回的值用於統計答題正確率和分數。
x, y = pygame.mouse.get_pos() # 獲取鼠標的位置 pressed = pygame.mouse.get_pressed() # 獲取鼠標的事件 # 四個答案區域的內容的鼠標鼠標時間控制 if item1_rect.left < x < item1_rect.right and item1_rect.top < y < item1_rect.bottom: item1_image = answerFont.render('1 - ' + level_answer[0], True, color_dict['gold']) SURFACE.blit(item1_image, item1_rect) for event in pressed: if event == 1: if level_correct == 1: return 'yes' else: return 'no' # 其他三個答案的判斷同理,不再重復演示
4. 最好把完成的代碼使用pyinstaller打包成exe文件,這里我是在一個32位的window系統下打包的,所以文件可以在32位和64位的window系統中直接執行。
pyinstall -F answer.py -i img/delbrucks-brain.ico
### 運行效果與文件截圖
1. 游戲的初始標題界面

2. 游戲的主界面,也就是游戲界面

3. 游戲的結束統計界面

4. 關於游戲界面

5. 項目的結構,font文件夾為游戲需要的字體,img文件夾為用到圖片文件

6. 壓縮包下載后解壓出來是長這個樣子

### 其他補充
使用了pyinstaller將整個項目打包成exe文件,可以在不安裝python運行環境的情況下運行體驗,可以自行修改data.xml文件。修改里面的題目,形成自己新的題庫。
如果需要移植到mac或者linux系統中運行,也是可以的,理論上可能需要修改字體文件即可,但本人未測試。如果需要請自行測試。
源碼里面有一段在測試的時候作弊用的代碼,注釋掉,沒有刪除,如果有興趣可以按照那個思路去做一些所謂的作弊,但其實作為答題游戲,也沒有什么可以作弊的,無非就是提示和顯示答案。Pygame制作答題類游戲的實現
> 代碼地址如下:<br>http://www.demodashi.com/demo/13495.html
> 注:本文著作權歸作者,由demo大師代發,拒絕轉載,轉載需要作者授權