利用Python編寫一個(gè)記憶翻牌游戲
導(dǎo)語(yǔ)
昨天看到有留言竟然說(shuō)我是月更博主,我明明更新地這么勤快(心虛.jpg)??窗?,昨天剛更新過(guò),今天又來(lái)更新了。
今天還是帶大家寫個(gè)小游戲吧,不過(guò)老是用pygame也沒(méi)啥意思,這次我們換點(diǎn)新花樣,用python自帶的tkinter包寫一個(gè)記憶翻牌小游戲唄。
廢話不多說(shuō),讓我們愉快地開(kāi)始吧~
開(kāi)發(fā)工具
Python版本:3.7.4
相關(guān)模塊:
pygame模塊;
tkinter模塊;
pillow模塊;
以及一些python自帶的模塊。
環(huán)境搭建
安裝Python并添加到環(huán)境變量,pip安裝需要的相關(guān)模塊即可。
先睹為快
在終端運(yùn)行如下命令即可:
python Game27.py
效果如下:
原理簡(jiǎn)介
ok,這里我們還是來(lái)簡(jiǎn)單介紹一下游戲的實(shí)現(xiàn)原理吧。
首先,我們還是借助pygame來(lái)播放一首我們喜歡的背景音樂(lè)吧:
'''播放背景音樂(lè)''' def playbgm(self): pygame.init() pygame.mixer.init() pygame.mixer.music.load(cfg.AUDIOPATHS['bgm']) pygame.mixer.music.play(-1, 0.0)
然后,我們初始化一下tkinter的主界面:
# 主界面句柄 self.root = Tk() self.root.wm_title('Flip Card by Memory —— Charles的皮卡丘')
并在主界面上顯示16張未被翻面的卡片:
# 游戲界面中的卡片字典 self.game_matrix = {} # 背景圖像 self.blank_image = PhotoImage(data=cfg.IMAGEPATHS['blank']) # 卡片背面 self.cards_back_image = PhotoImage(data=cfg.IMAGEPATHS['cards_back']) # 所有卡片的索引 cards_list = list(range(8)) + list(range(8)) random.shuffle(cards_list) # 在界面上顯示所有卡片的背面 for r in range(4): for c in range(4): position = f'{r}_{c}' self.game_matrix[position] = Label(self.root, image=self.cards_back_image) self.game_matrix[position].back_image = self.cards_back_image self.game_matrix[position].file = str(cards_list[r * 4 + c]) self.game_matrix[position].show = False self.game_matrix[position].bind('<Button-1>', self.clickcallback) self.game_matrix[position].grid(row=r, column=c)
這16張卡片共包含8張完全不同的圖像,我們游戲的目標(biāo)就是在有限的時(shí)間內(nèi),將16張卡片中包含相同的圖像的卡片兩兩配對(duì)。匹配的規(guī)則是鼠標(biāo)連續(xù)地點(diǎn)擊兩張卡片,若卡片背面的圖像相同,則匹對(duì)成功,否則配對(duì)失敗。游戲主要考察玩家的記憶力,因?yàn)橛螒蜻€規(guī)定游戲翻開(kāi)的卡片數(shù)量至多有兩張,否則一開(kāi)始被點(diǎn)擊而翻開(kāi)的卡片將再次被蓋上(若該張卡片沒(méi)有匹對(duì)成功)。
接著,我們來(lái)定義一些有用的變量:
# 已經(jīng)顯示正面的卡片 self.shown_cards = [] # 場(chǎng)上存在的卡片數(shù)量 self.num_existing_cards = len(cards_list) # 顯示游戲剩余時(shí)間 self.num_seconds = 30 self.time = Label(self.root, text=f'Time Left: {self.num_seconds}') self.time.grid(row=6, column=3, columnspan=2)
并讓界面一開(kāi)始可以出現(xiàn)在電腦屏幕的居中位置:
# 居中顯示 self.root.withdraw() self.root.update_idletasks() x = (self.root.winfo_screenwidth() - self.root.winfo_reqwidth()) / 2 y = (self.root.winfo_screenheight() - self.root.winfo_reqheight()) / 2 self.root.geometry('+%d+%d' % (x, y)) self.root.deiconify()
由于是在有限的時(shí)間內(nèi)完成所有卡片的匹對(duì),所以我們來(lái)寫一個(gè)定時(shí)函數(shù),并實(shí)時(shí)等更新顯示當(dāng)前游戲的剩余時(shí)間:
'''計(jì)時(shí)''' def tick(self): if self.num_existing_cards == 0: return if self.num_seconds != 0: self.num_seconds -= 1 self.time['text'] = f'Time Left: {self.num_seconds}' self.time.after(1000, self.tick) else: is_restart = messagebox.askyesno('Game Over', 'You fail since time up, do you want to play again?') if is_restart: self.restart() else: self.root.destroy()
最后,我們?cè)谑髽?biāo)左鍵點(diǎn)擊卡片時(shí),用代碼定義一下游戲的響應(yīng)規(guī)則,以實(shí)現(xiàn)我們想要的功能:
'''點(diǎn)擊回調(diào)函數(shù)''' def clickcallback(self, event): card = event.widget if card.show: return # 之前沒(méi)有卡片被翻開(kāi) if len(self.shown_cards) == 0: self.shown_cards.append(card) image = ImageTk.PhotoImage(Image.open(os.path.join(self.card_dir, card.file+'.png'))) card.configure(image=image) card.show_image = image card.show = True # 之前只有一張卡片被翻開(kāi) elif len(self.shown_cards) == 1: # --之前翻開(kāi)的卡片和現(xiàn)在的卡片一樣 if self.shown_cards[0].file == card.file: def delaycallback(): self.shown_cards[0].configure(image=self.blank_image) self.shown_cards[0].blank_image = self.blank_image card.configure(image=self.blank_image) card.blank_image = self.blank_image self.shown_cards.pop(0) self.score_sound.play() self.num_existing_cards -= 2 image = ImageTk.PhotoImage(Image.open(os.path.join(self.card_dir, card.file+'.png'))) card.configure(image=image) card.show_image = image card.show = True card.after(300, delaycallback) # --之前翻開(kāi)的卡片和現(xiàn)在的卡片不一樣 else: self.shown_cards.append(card) image = ImageTk.PhotoImage(Image.open(os.path.join(self.card_dir, card.file+'.png'))) card.configure(image=image) card.show_image = image card.show = True # 之前有兩張卡片被翻開(kāi) elif len(self.shown_cards) == 2: # --之前翻開(kāi)的第一張卡片和現(xiàn)在的卡片一樣 if self.shown_cards[0].file == card.file: def delaycallback(): self.shown_cards[0].configure(image=self.blank_image) self.shown_cards[0].blank_image = self.blank_image card.configure(image=self.blank_image) card.blank_image = self.blank_image self.shown_cards.pop(0) self.score_sound.play() self.num_existing_cards -= 2 image = ImageTk.PhotoImage(Image.open(os.path.join(self.card_dir, card.file+'.png'))) card.configure(image=image) card.show_image = image card.show = True card.after(300, delaycallback) # --之前翻開(kāi)的第二張卡片和現(xiàn)在的卡片一樣 elif self.shown_cards[1].file == card.file: def delaycallback(): self.shown_cards[1].configure(image=self.blank_image) self.shown_cards[1].blank_image = self.blank_image card.configure(image=self.blank_image) card.blank_image = self.blank_image self.shown_cards.pop(1) self.score_sound.play() self.num_existing_cards -= 2 image = ImageTk.PhotoImage(Image.open(os.path.join(self.card_dir, card.file+'.png'))) card.configure(image=image) card.show_image = image card.show = True card.after(300, delaycallback) # --之前翻開(kāi)的卡片和現(xiàn)在的卡片都不一樣 else: self.shown_cards.append(card) self.shown_cards[0].configure(image=self.cards_back_image) self.shown_cards[0].show = False self.shown_cards.pop(0) image = ImageTk.PhotoImage(Image.open(os.path.join(self.card_dir, card.file+'.png'))) self.shown_cards[-1].configure(image=image) self.shown_cards[-1].show_image = image self.shown_cards[-1].show = True # 判斷游戲是否已經(jīng)勝利 if self.num_existing_cards == 0: is_restart = messagebox.askyesno('Game Over', 'Congratulations, you win, do you want to play again?') if is_restart: self.restart() else: self.root.destroy()
ok,大功告成。代碼邏輯比較簡(jiǎn)單,就不展開(kāi)講啦,小伙伴們簡(jiǎn)單看下,肯定就能看懂啦。
到此這篇關(guān)于利用Python編寫一個(gè)記憶翻牌游戲的文章就介紹到這了,更多相關(guān)Python翻牌游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于Python編寫一個(gè)簡(jiǎn)單的端口掃描器
端口掃描是非常實(shí)用的,不止用在信息安全方面,日常的運(yùn)維也用得到。本文將利用Python編寫一個(gè)簡(jiǎn)單的端口掃描器,需要的可以參考一下2022-04-04python 循環(huán)讀取txt文檔 并轉(zhuǎn)換成csv的方法
今天小編就為大家分享一篇python 循環(huán)讀取txt文檔 并轉(zhuǎn)換成csv的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10使用Python通過(guò)win32 COM打開(kāi)Excel并添加Sheet的方法
今天小編就為大家分享一篇使用Python通過(guò)win32 COM打開(kāi)Excel并添加Sheet的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05git使用.gitignore設(shè)置不生效或不起作用問(wèn)題的解決方法
下面小編就為大家?guī)?lái)一篇git使用.gitignore設(shè)置不生效或不起作用問(wèn)題的解決方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06Python3自動(dòng)安裝第三方庫(kù),跟pip說(shuō)再見(jiàn)
很多朋友私信小編Python安裝第三方庫(kù)安裝技巧,在這就不一一回復(fù)大家了,今天小編給大家分享一篇教程關(guān)于Python自動(dòng)安裝第三方庫(kù)的小技巧,本文以安裝plotly為例給大家詳細(xì)講解,感興趣的朋友跟隨小編一起看看吧2021-10-10利用Python中SocketServer 實(shí)現(xiàn)客戶端與服務(wù)器間非阻塞通信
本文主要介紹了利用Python中SocketServer 實(shí)現(xiàn)客戶端與服務(wù)器間非阻塞通信示例代碼,具有很好的參考價(jià)值,需要的朋友一起來(lái)看下吧2016-12-12