利用Python编写一个记忆翻牌游戏

作者:Charles的皮卡丘 时间:2022-09-24 02:20:54 

导语

昨天看到有留言竟然说我是月更博主,我明明更新地这么勤快(心虚.jpg)。看吧,昨天刚更新过,今天又来更新了。

今天还是带大家写个小游戏吧,不过老是用pygame也没啥意思,这次我们换点新花样,用python自带的tkinter包写一个记忆翻牌小游戏呗。

废话不多说,让我们愉快地开始吧~

开发工具

Python版本:3.7.4

相关模块:

pygame模块;

tkinter模块;

pillow模块;

以及一些python自带的模块。

环境搭建

安装Python并添加到环境变量,pip安装需要的相关模块即可。

先睹为快

在终端运行如下命令即可:

python Game27.py

效果如下:

视频链接

原理简介

ok,这里我们还是来简单介绍一下游戏的实现原理吧。

首先,我们还是借助pygame来播放一首我们喜欢的背景音乐吧:

'''播放背景音乐'''
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张完全不同的图像,我们游戏的目标就是在有限的时间内,将16张卡片中包含相同的图像的卡片两两配对。匹配的规则是鼠标连续地点击两张卡片,若卡片背面的图像相同,则匹对成功,否则配对失败。游戏主要考察玩家的记忆力,因为游戏还规定游戏翻开的卡片数量至多有两张,否则一开始被点击而翻开的卡片将再次被盖上(若该张卡片没有匹对成功)。

接着,我们来定义一些有用的变量:

# 已经显示正面的卡片
self.shown_cards = []
# 场上存在的卡片数量
self.num_existing_cards = len(cards_list)
# 显示游戏剩余时间
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)

并让界面一开始可以出现在电脑屏幕的居中位置:

# 居中显示
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()

由于是在有限的时间内完成所有卡片的匹对,所以我们来写一个定时函数,并实时等更新显示当前游戏的剩余时间:

'''计时'''
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()

最后,我们在鼠标左键点击卡片时,用代码定义一下游戏的响应规则,以实现我们想要的功能:

'''点击回调函数'''
def clickcallback(self, event):
   card = event.widget
   if card.show: return
   # 之前没有卡片被翻开
   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
   # 之前只有一张卡片被翻开
   elif len(self.shown_cards) == 1:
       # --之前翻开的卡片和现在的卡片一样
       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)
       # --之前翻开的卡片和现在的卡片不一样
       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
   # 之前有两张卡片被翻开
   elif len(self.shown_cards) == 2:
       # --之前翻开的第一张卡片和现在的卡片一样
       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)
       # --之前翻开的第二张卡片和现在的卡片一样
       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)
       # --之前翻开的卡片和现在的卡片都不一样
       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
   # 判断游戏是否已经胜利
   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,大功告成。代码逻辑比较简单,就不展开讲啦,小伙伴们简单看下,肯定就能看懂啦。

来源:https://zhuanlan.zhihu.com/p/373217730

标签:Python,记忆,翻牌,游戏
0
投稿

猜你喜欢

  • SQL Server中如何快速获取表的记录总数

    2008-12-05 15:59:00
  • Python中True(真)和False(假)判断详解

    2021-12-16 11:22:36
  • 善用用户反馈——浅谈用户反馈数据的处理

    2010-07-09 16:58:00
  • 一文带你了解Python中的输入与输出

    2023-11-26 12:05:24
  • Python使用graphviz画流程图过程解析

    2022-06-19 06:45:18
  • 互联网产品的用户体验看着“很美”

    2009-07-07 12:04:00
  • windows下Python安装、使用教程和Notepad++的使用教程

    2023-04-21 09:31:39
  • Python脚本实现虾米网签到功能

    2021-11-23 14:37:53
  • 深入透析样式表滤镜(上)

    2011-06-14 09:48:40
  • PyCharm Community安装与配置的详细教程

    2022-05-03 18:20:40
  • Python实现查看系统启动项功能示例

    2022-12-27 17:03:14
  • SqlServer参数化查询之where in和like实现详解

    2012-05-22 18:10:50
  • 使用PHP 5.0创建图形的巧妙方法

    2023-10-27 00:59:07
  • vscode+PyQt5安装详解步骤

    2021-07-27 23:52:55
  • Python实现微信好友的数据分析

    2023-10-21 15:54:20
  • Apache2.4.x版wampserver本地php服务器如何让外网访问及启用.htaccess

    2023-11-04 09:27:00
  • python使用wxpy实现微信消息防撤回脚本

    2023-08-22 21:21:58
  • 关于Python中进度条的六个实用技巧分享

    2023-07-03 09:58:39
  • Pandas过滤dataframe中包含特定字符串的数据方法

    2021-10-11 13:39:08
  • 如何让shell终端和goland控制台输出彩色的文字

    2023-07-13 03:24:56
  • asp之家 网络编程 m.aspxhome.com