文章目录

  • 前言
  • 看图猜成语
    • 1. 玩法简介
    • 2. 游戏流程
    • 3. 代码实现
      • 1). 创建成语库及初始化
        • OS内置模块
      • 2). 随机抽取成语
        • 随机选词
        • 绘制图片
        • 准备汉字库
        • 按钮上的汉字
      • 3). 重新定义选字按钮
        • 显示玩家选择的汉字
        • 自定义按钮类
      • 4). 判断玩家的选择
      • 5). 清空选择
      • 6). 电脑提示
    • 4. 完整代码
  • 总结与思考

前言

大家好,上篇我们把游戏的样子已经搭起来了,今天我们就继续未完成的内容,用代码实现游戏的功能,废话不多说,让我们开始吧。

上篇 —— 游戏界面的搭建
下篇 —— 后台程序的实现


看图猜成语

1. 玩法简介

上篇中已经介绍过玩法,这里简单带过,相信大家一看就懂。

游戏截图:

2. 游戏流程

上篇中我们已经画了一个流程图:

#mermaid-svg-D05sQcjY0xptmdVL {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-D05sQcjY0xptmdVL .error-icon{fill:#552222;}#mermaid-svg-D05sQcjY0xptmdVL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-D05sQcjY0xptmdVL .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-D05sQcjY0xptmdVL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-D05sQcjY0xptmdVL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-D05sQcjY0xptmdVL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-D05sQcjY0xptmdVL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-D05sQcjY0xptmdVL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-D05sQcjY0xptmdVL .marker.cross{stroke:#333333;}#mermaid-svg-D05sQcjY0xptmdVL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-D05sQcjY0xptmdVL .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-D05sQcjY0xptmdVL .cluster-label text{fill:#333;}#mermaid-svg-D05sQcjY0xptmdVL .cluster-label span{color:#333;}#mermaid-svg-D05sQcjY0xptmdVL .label text,#mermaid-svg-D05sQcjY0xptmdVL span{fill:#333;color:#333;}#mermaid-svg-D05sQcjY0xptmdVL .node rect,#mermaid-svg-D05sQcjY0xptmdVL .node circle,#mermaid-svg-D05sQcjY0xptmdVL .node ellipse,#mermaid-svg-D05sQcjY0xptmdVL .node polygon,#mermaid-svg-D05sQcjY0xptmdVL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-D05sQcjY0xptmdVL .node .label{text-align:center;}#mermaid-svg-D05sQcjY0xptmdVL .node.clickable{cursor:pointer;}#mermaid-svg-D05sQcjY0xptmdVL .arrowheadPath{fill:#333333;}#mermaid-svg-D05sQcjY0xptmdVL .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-D05sQcjY0xptmdVL .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-D05sQcjY0xptmdVL .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-D05sQcjY0xptmdVL .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-D05sQcjY0xptmdVL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-D05sQcjY0xptmdVL .cluster text{fill:#333;}#mermaid-svg-D05sQcjY0xptmdVL .cluster span{color:#333;}#mermaid-svg-D05sQcjY0xptmdVL div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-D05sQcjY0xptmdVL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

No
Yes
Yes
No
游戏开始
画面展示
玩家选择汉字组成成语
判断玩家输入是否正确
清空玩家的选择
恭喜,是否进入下一关
重新选词
游戏结束
玩家选择提示

这里我们再回顾下,可以帮助我们了解到需要创建哪些自定义函数。在上篇中可以说我们已经完成了“画面展示”的部分,唯一需要对其进行补充的,是如何随机显示成语图片,已经玩家回答正确后,切换至下一张。

此外,我们还需要完成以下功能的程序或自定义函数:

  1. 创建成语库,并随机抽取单个成语
  2. 判断玩家选择是否正确
  3. 清空玩家选择
  4. 提示一个汉字

让我们逐个来讲解。

3. 代码实现

1). 创建成语库及初始化

问哥从网上下载了444个看图猜成语的图片,上传在这里,或者也可以私信问哥领取。

这些图片有三个特点:

  1. 大小一致,都是120x120
  2. 都是PNG图片
  3. 都是以各自所代表的成语命名

前两个特点方便我们在程序里展示,不用再写代码去调整图片大小的位置。第三个特点更是方便我们创建成语库,我们只需要把所有成语图片放在文件夹images下,再提取该文件夹下所有文件的名称(格式均为xxxx.png),然后选取前4个字符就是我们的成语库了。调用的时候,我们只要先确定好成语,再在成语后面加上.png就是对应的图片了。

OS内置模块

提取文件夹下所有文件的名称,需要用到Python的另一个内置模块os。顾名思义,这个模块就是和操作系统(operation system)相关的。用起来也很简单:

import os
filenames = os.listdir(r'images\words')

只需要使用os模块里的listdir方法,就可以把文件夹下所有的文件名都提取出来,返回一个列表。(因为问哥把背景图片也放在了images文件夹下,所以为了省事,又在下面创建了一个words文件夹专门用来存放成语图片。)

得到这个列表后,我们就可以使用列表切片操作,提取每个字符串的前四个字符,组成成语列表了。

word_list = [i[:4] for i in filenames]

当然,我们希望每次开始玩游戏的时候,成语显示都是随机的,所以我们需要使用前面学到过的random.shuffle方法把这些列表随机打散,就像洗牌一样,然后每次从牌堆顶或底抽取一张,成为我们让玩家猜的成语。

import random
random.shuffle(word_list)

这样我们就创建好了成语库,也完成了初始化(洗牌)。

2). 随机抽取成语

考虑到抽取成语的动作是在每个关卡都要操作的,所以还是自定义一个函数来实现比较方便,这样可以省去重复书写的代码。这里问哥为这个函数取名create_random_word()

随机选词

我们先自定义一个全局变量word,用来保存每个关卡电脑抽取的正确成语。随着游戏进行,我们需要在自定义函数里不断地改变这个变量的值(每次抽取的成语都不一样),所以最好是在函数内部使用global关键字把它声明为全局变量,免去传参的烦恼。

此外,因为在初始化的过程中,我们已经使用shuffle方法把成语库的顺序打乱,所以在抽取成语的时候我们就不需要再使用随机方法,而是直接从成语库(牌堆)的顶或底取一张就可以。问哥使用的是列表的pop()方法,也就是从列表的末端(牌堆的底部)抽取一张,同时成语列表的元素减一。代码实现如下:

word=''
def create_random_word():global wordword = word_list.pop()

现在我们就可以把随机选择的成语所对应的图片绘制到Canvas画布上了。

上篇中,我们是静态地定义了图片,回顾一下:

img = tk.PhotoImage(file=f"images\words\一帆风顺.png")
cv_word = cv.create_image(150,120,image = img)

绘制图片

现在我们有了自定义函数,就要把这两句代码移动到自定义函数中去。但是需要注意的是,绘制在Canvas画布上的img图片变量需要带到主窗口的循环中(mainloop),如果移动到自定义函数中变成局部变量的话,一旦程序运行离开自定义函数,这个变量就消失了,图片也就为没有了。所以,我们需要把img也声明成全局变量。

可以直接在global关键字里一起声明,并用逗号分隔开。

word=''
def create_random_word():global word, imgword = word_list.pop()img = tk.PhotoImage(file=f"images\words\{word}.png")cv.create_image(150,120,image = img)

现在我们可以把这个函数在最后调用,(注意,要放在cv.pack()的前面,不然成语图片画不上去)

create_random_word()
cv.pack() # 在主窗口装载画布
root.mainloop() # 主窗口循环展示

检查看看效果:

准备汉字库

图片是有了,而且还有一个全局变量word,用来代表图片所对应的正确成语。但是我们还需要为玩家准备一个可供选择的汉字库。这样玩家将可以从中选取正确的汉字组成成语。

我们定义一个局部列表变量lib来代表这个字库。同时我们必须要确保字库里有正确成语word,还要有另外4个随机的成语,当做干扰答案。所以我们可以使用random.sample方法从剩下的成语库里随机算出4个成语来,然后用字符串拼接的方法(“join”和“+”)和正确成语word组成一个20个汉字的字符串。接着再把这20个汉字的字符串转成列表装进lib。最后再使用random.shuffle方法把这个列表打乱,以保证我们最后显示的字库是乱序的。代码如下:

def create_random_word():lib = list(''.join(random.sample(word_list,4))+word)random.shuffle(lib)

但是这里有个小问题,我们是从“牌堆”(word_list)中随机选取另外4个成语,随着游戏的进行,“牌堆”必定会越来越少。当只剩下少于4个成语的时候,这种取样方式必定会报错,所以我们必须想办法保证即使是最后一个成语,也能找到另外4个干扰成语组成lib。

如果把成语词库比作牌堆,我们必然会有另一个牌堆列表——弃牌堆,所以我们可以考虑利用弃牌堆。定义一个新的空列表word_copy,用来收集每次用完后的成语word。只要word不为空(游戏刚开始时),就把这个词加入“弃牌堆”列表word_copy。然后在随机选取的时候,我们可以从“弃牌堆”和“牌堆”这两个列表里选,问题就可以解决了。修改后代码如下:

word=''
word_copy = []
def create_random_word():global word, img, word_copyif word: word_copy.append(word)word = word_list.pop()lib = list(''.join(random.sample(word_copy+word_list,4))+word)

这样我们就准备好了20个(5个成语)乱序的汉字,现在只要把它们“写”到按钮上就好了。

按钮上的汉字

还记得上篇我们已经准备好了20个光秃秃的按钮吗?

for i in range(4):for j in range(5):btn = tk.Button(root, font =('方正楷体简体',11),width=2,relief='flat',bg='lightyellow')btn_window = cv.create_window(300+40*i, 75+35*j, window=btn)

现在我们可以把lib里的汉字写在按钮上了,但是当时为了方便布置按钮,我们把所有的按钮都取名叫btn,现在我们想在每个按钮上写上不同汉字的时候,就必须知道每个按钮的名字了。所以我们定义一个按钮的列表,把所有按钮都放在列表里,这样通过列表索引就可以引用不同的按钮了。于是,这部分代码修改如下:

btn = []
for i in range(4):for j in range(5):btn.append(tk.Button(root, font =('方正楷体简体',11),width=2,relief='flat',bg='lightyellow'))btn_window = cv.create_window(300+40*i, 75+35*j, window=btn[i*5+j])

现在我么可以在create_random_word函数里在这20个按钮上写上汉字了,只要依次修改它们的text属性。所以最后create_random_word函数的代码如下:

word=''
word_copy=[]
def create_random_word():global word, img, word_copyif word: word_copy.append(word) # “弃牌堆”word = word_list.pop() # 抽取新的成语lib = list(''.join(random.sample(word_copy+word_list,4))+word)random.shuffle(lib) # 准备干扰字库for i in range(len(btn)):btn[i]['text'] = lib[i] # 在按钮上写汉字img = tk.PhotoImage(file=f"images\words\{word}.png")cv.create_image(150,120,image = img) # 把图片画在指定位置

运行看看效果:

3). 重新定义选字按钮

现在摆在我们面前的有两个问题:

  1. 怎样实现点击按钮,就能得到相对应的汉字;
  2. 怎样把玩家通过点击按钮得到的汉字显示在图片下面那四个正方形的格子里。

我们先来说第2个问题,因为这个比较好实现。

显示玩家选择的汉字

在上篇里,那四个正方形的格子其实就是普通的矩形,我们没法在里面写字。

for i in range(4):cv.create_rectangle(50*i+50,210,50*i+86,246,fill='ivory')

但是我们可以在它们上面写字。假设玩家选择的汉字组成的字符串变量是txt,那我们只要在相应的位置用画布的create_text方法创建4个文本就可以了。

txt = '接二连三'
for i in range(4):cv.create_text(50*i+68,228,fill='black', text=txt[i], font =('方正楷体简体',18,'bold'))

但是因为我们还要随时改变这四个文本,所以最好还是把它们也放在数组里。代码修改如下:

txt = '接二连三'
text=[]
for i in range(4):text.append(cv.create_text(50*i+68,228,fill='black',text=txt[i], font =('方正楷体简体',18,'bold')))

看看效果:

接下来我们只要通过按钮去改变变量txt的值就好了。当然在游戏开始的时候,txt的值应该为空(“”)。

自定义按钮类

现在看看我们刚刚说的第一个问题。tkinter的按钮组件都可以添加一个command参数,用来指定按下该按钮后需要执行的函数。但是问题在于,这个command指定的函数不能传参,而我们的按钮却需要在被按下的时候执行不同的动作(把按钮上的字添加进txt里)。

这个时候我们可以使用面向对象编程的方法,把每个按钮想象成一个有生命的物体。每个按钮有他自己的方法,就是把自己的名字添加进txt。除此之外,这些按钮还需要和tkinter的Button类有一样的属性和方法。于是我们可以创建一个子类,继承tkinter的Button类。因为只需要添加一个自己独特的方法,所以不需要定义初始化,默认让类成员使用tkinter的Button类初始化。代码如下:

class MyButton(tk.Button):def click(self):global txtif len(txt)<4: # 判断玩家是不是已经选了4个汉字txt+=self['text'] # 把按钮自己的汉字添加进txtfor i in range(len(txt)):cv.itemconfig(text[i],text=txt[i]) # 改变文本的内容self.config(state=tk.DISABLED)

self就代表了每个调用click方法的按钮实例。在这个方法里,我们需要判断txt是不是已经有4个字符了(因为只有4个汉字),如果没有的话,我们把就把按钮上的汉字(self[‘text’])添加进txt里。同时,根据变化的txt,使用canvas的itemconfig方法来改变文本组件text的值。这样就可以达到根据玩家的选择不同,文本的内容实时变化的效果。然后,当玩家选择了某个汉字(按下了某个按钮),我们想要那个按钮变成灰色不可选的状态,于是可以直接使用self.config方法将按钮的状态变成DISABLED(也可以直接用字典的方式调用,self[‘state’]=tk.DISABLED)。

最后,我们只要把之前创建的按钮改成这个新的子类,再把之前的循环放在一起,代码修改如下:

txt = ''
text=[]
btn = []
for i in range(4):cv.create_rectangle(50*i+50,210,50*i+86,246,fill='ivory')text.append(cv.create_text(50*i+68,228,fill='black', font =('方正楷体简体',18,'bold')))for j in range(5):btn.append(MyButton(root, font =('方正楷体简体',11),width=2,relief='flat',bg='lightyellow'))btn_window = cv.create_window(300+40*i, 75+35*j, window=btn[i*5+j])
for i in btn:i['command']=i.click

实现效果如下:

4). 判断玩家的选择

在我们刚才新建立的按钮子类的click方法里,我们需要先判断玩家选择的汉字有没有达到4个。如果达到4个,我们就需要对其进行判断。所以我们在click方法里,加上以下代码:

        if len(txt)==4:is_winner()

如果txt的长度为4,即说明有4个汉字被选中的话,调用is_winner()方法,来判断玩家是否获胜,以及后续的操作。于是我们开始编写is_winner()方法,或者称之为自定义函数。

这个自定义函数要实现的功能其实有不少,我们画一个局部流程图来加以讲解。

#mermaid-svg-t09cQyV3u0tVxa7w {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-t09cQyV3u0tVxa7w .error-icon{fill:#552222;}#mermaid-svg-t09cQyV3u0tVxa7w .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-t09cQyV3u0tVxa7w .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-t09cQyV3u0tVxa7w .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-t09cQyV3u0tVxa7w .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-t09cQyV3u0tVxa7w .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-t09cQyV3u0tVxa7w .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-t09cQyV3u0tVxa7w .marker{fill:#333333;stroke:#333333;}#mermaid-svg-t09cQyV3u0tVxa7w .marker.cross{stroke:#333333;}#mermaid-svg-t09cQyV3u0tVxa7w svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-t09cQyV3u0tVxa7w .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-t09cQyV3u0tVxa7w .cluster-label text{fill:#333;}#mermaid-svg-t09cQyV3u0tVxa7w .cluster-label span{color:#333;}#mermaid-svg-t09cQyV3u0tVxa7w .label text,#mermaid-svg-t09cQyV3u0tVxa7w span{fill:#333;color:#333;}#mermaid-svg-t09cQyV3u0tVxa7w .node rect,#mermaid-svg-t09cQyV3u0tVxa7w .node circle,#mermaid-svg-t09cQyV3u0tVxa7w .node ellipse,#mermaid-svg-t09cQyV3u0tVxa7w .node polygon,#mermaid-svg-t09cQyV3u0tVxa7w .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-t09cQyV3u0tVxa7w .node .label{text-align:center;}#mermaid-svg-t09cQyV3u0tVxa7w .node.clickable{cursor:pointer;}#mermaid-svg-t09cQyV3u0tVxa7w .arrowheadPath{fill:#333333;}#mermaid-svg-t09cQyV3u0tVxa7w .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-t09cQyV3u0tVxa7w .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-t09cQyV3u0tVxa7w .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-t09cQyV3u0tVxa7w .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-t09cQyV3u0tVxa7w .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-t09cQyV3u0tVxa7w .cluster text{fill:#333;}#mermaid-svg-t09cQyV3u0tVxa7w .cluster span{color:#333;}#mermaid-svg-t09cQyV3u0tVxa7w div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-t09cQyV3u0tVxa7w :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

Yes
Yes
Yes
Yes
No
No
猜中
No
No
未猜中
开始判断
玩家是否猜中?
弹出对话框,询问是否继续
判断是否已猜完词库
询问玩家是否重新开始
重新导入词库,关卡清零
从头开始游戏
游戏结束
清空玩家的选择
调用create_random_word
回到游戏

由此可见,当玩家选择正确的时候,要做的事情还真不少:

  1. 询问是否继续
  2. 检查词库是否猜完
  3. 询问是否重头再玩一次

我先把代码贴出来:

import tkinter.messagebox as tm
def is_winner():global word, txt, level, word_listif txt==word:for i in btn:i.config(state=tk.DISABLED)result=tm.askquestion ("恭喜","恭喜你,答对了!继续下一题吗?")if result == 'yes':if len(word_list)==0:newgame = tm.askquestion ("恭喜",f'恭喜你!你已经通过了全部{level}关,继续从头开始游戏吗?')if newgame == 'yes':word_list = [i[:4] for i in filenames]random.shuffle(word_list)level = 0else:root.destroy()level += 1cv.itemconfig(level_indicator,text=f'第 {level} 关')clean_word()create_random_word()else:tm.showinfo(title='再见', message=f'您一共通过了{level}关')root.destroy()else:clean_word()

首先,为了实现windows消息框的效果,我们需要导入tkinter的另一个子模块messagebox。使用下面的语句将模块导入,并简写为tm

import tkinter.messagebox as tm

然后就可以使用tkinter自带的几种消息框了。在这个小游戏中我们只要用到两种就够了,一种是在询问玩家是否继续的时候,需要得到玩家的选择,另一种是不需要玩家进行选择,只是通知玩家一些信息。前者我们使用的是tm的askquestion方法,该方法根据用户的选择不同,返回一个字符串,要么是“yes”,要么是“no”。

后者仅仅是一个通知消息框,待玩家鼠标点击“确认”后,程序自动执行后面的命令,也就是“销毁”主窗口,退出游戏。

root.destroy()


需要注意的是,如果玩家真的把所有成语都猜过了,又选择重新开始的时候,需要在这里把word_list重新初始化一遍(从文件名导入成语、随机打乱)。同时还要把关卡计数清零,从头开始计数。

而不管是猜错了,还是猜对后再开始一局,都需要调用另一个自定义函数clean(),用来把文本框里玩家选择的4个汉字清空。

5). 清空选择

清空选择的自定义函数就比较简单了,但也要完成三件事:

  1. 清空玩家选择的汉字变量txt
  2. 清空Canvas画布上的文本框
  3. 把所有按钮的状态全部变成NORMAL(因为有些按钮在按下后被设置成了DISABLE),这样玩家才能重新选择。

代码实现如下:

def clean_word():global txttxt = ''for i in range(4):cv.itemconfig(text[i],text='')for i in btn:i.config(state=tk.NORMAL)

同时我们在游戏的右下角还有另外两个按钮,“清空”和“提示”。现在我们可以直接把自定义函数clean_word()绑定到“清空”按钮上了。

btn_clean=ttk.Button(root, text='清空', width=5, command=clean_word)

6). 电脑提示

最后的一步,是电脑提示按钮。其实问哥觉得这个按钮有点多余,基本上不会遇到猜不出的情况。但是考虑到可以把游戏进行变种,比如不采用选汉字的方式猜成语,而是让玩家手工输入(需要增加Entry输入框或使用Label组件),难度就会大大增加了,那样的话电脑提示可能还是有点作用的。所以这里我们先把功能做出来,要不要用再说。

其实说来也很简单,就是随机选一个汉字,然后让Canvas的文本框显示那个汉字就好。于是我们可以定义一个局部变量hint_word,然后再使用随机函数生成一个0到3的数字,代表我们要选取的汉字在成语中的位置。然后再将hint_word赋值给文本框就好了。

同时不要忘记,玩家有可能猜了一两个字然后使用提示的情况,这样一些按钮状态可能是DISABLED,所以我们需要在这里把所有按钮的状态恢复成NORMAL。

代码如下:

def hint():global wordhint_word = ['']*4i = random.randint(0,3)hint_word[i] = word[i]for i in range(4):cv.itemconfig(text[i],text=hint_word[i])for i in btn:i.config(state=tk.NORMAL)

最后,别忘记把这个自定义函数绑定在“提示”按钮上。

btn_submit=ttk.Button(root, text='提示', width=5, command=hint)

4. 完整代码

到这里,我们这个小游戏就编写完成了。大家不妨分享给你的小伙伴一起玩玩看。

附上完整代码:

import tkinter as tk
from tkinter import ttk
import tkinter.messagebox as tm
import os
import randomclass MyButton(tk.Button):def click(self):global txtif len(txt)<4:txt+=self['text']for i in range(len(txt)):cv.itemconfig(text[i],text=txt[i])self.config(state=tk.DISABLED)if len(txt)==4:is_winner()def create_random_word():global word, img, word_copyif word: word_copy.append(word)word = word_list.pop()lib = list(''.join(random.sample(word_copy+word_list,4))+word)random.shuffle(lib)for i in range(len(btn)):btn[i]['text'] = lib[i]img = tk.PhotoImage(file=f"images\words\{word}.png")cv.create_image(150,120,image = img)def is_winner():global word, txt, level, word_listif txt==word:for i in btn:i.config(state=tk.DISABLED)result=tm.askquestion ("恭喜","恭喜你,答对了!继续下一题吗?")if result == 'yes':if len(word_list)==0:newgame = tm.askquestion ("恭喜",f'恭喜你!你已经通过了全部{level}关,继续从头开始游戏吗?')if newgame == 'yes':word_list = [i[:4] for i in filenames]random.shuffle(word_list)level = 0else:root.destroy()level += 1cv.itemconfig(level_indicator,text=f'第 {level} 关')clean_word()create_random_word()else:tm.showinfo(title='再见', message=f'您一共通过了{level}关')root.destroy()else:clean_word()def clean_word():global txttxt = ''for i in range(4):cv.itemconfig(text[i],text='')for i in btn:i.config(state=tk.NORMAL)def hint():global wordhint_word = ['']*4i = random.randint(0,3)hint_word[i] = word[i]for i in range(4):cv.itemconfig(text[i],text=hint_word[i])for i in btn:i.config(state=tk.NORMAL)# 游戏从这里开始
filenames = os.listdir(r'images\words')
word_list = [i[:4] for i in filenames]
random.shuffle(word_list)
# 初始化完成
word=''
word_copy=[]
txt = ''
text=[]
btn = []
level=1
# 开始创建GUI窗口
root = tk.Tk()
root.geometry("500x300")
root.resizable(0,0)
root.title('看图猜成语') cv=tk.Canvas(root,bg='white',width=500,height=300)
bg = tk.PhotoImage(file=r"images\bg.png")
cv_bg = cv.create_image(250,150,image = bg)
title = tk.PhotoImage(file=r"images\title.png")
cv_tt = cv.create_image(250,30,image = title)
cv.create_rectangle(90,60,210,180,fill='moccasin',outline = '')for i in range(4):cv.create_rectangle(50*i+50,210,50*i+86,246,fill='ivory')text.append(cv.create_text(50*i+68,228,fill='black', font =('方正楷体简体',18,'bold')))for j in range(5):btn.append(MyButton(root, font =('方正楷体简体',11),width=2,relief='flat',bg='lightyellow'))btn_window = cv.create_window(300+40*i, 75+35*j, window=btn[i*5+j])
for i in btn:i['command']=i.clickbtn_clean=ttk.Button(root, text='清空', width=5, command=clean_word)
btn_submit=ttk.Button(root, text='提示', width=5, command=hint)
cv.create_window(320, 265, window=btn_clean)
cv.create_window(400, 265, window=btn_submit)
level_indicator = cv.create_text(150,270,text=f'第 {level} 关', fill='black', font=('微软正楷',9,'bold'))create_random_word()
cv.pack()
root.mainloop()

总结与思考

经过一个星期的熬夜,问哥终于把这个小游戏完整地讲解出来了。不知道讲得够不够细致,大家还有没有不明白的呢?欢迎私信我或给我留言。同时,通过这个小游戏,我们也学习到了Python自带的图形化组件tkinter的一些基本操作,希望大家如果感到有问哥没有讲透彻的地方,也可以先通过在网上搜索同类文章加以学习掌握,或者直接私信问哥解答。

感谢大家读到这里,我们下次再见!

Python写个小游戏:看图猜成语(下)相关推荐

  1. python微信小程序看图猜成语源码flask

    wx供重浩:创享日记 对话框发送:python成语 获取完整源码源文件+说明文档+配置教程等 启动Idiom/flask下的venv虚拟环境,运行python manage.py runserver命 ...

  2. Python写个小游戏:蛇棋(下)

    文章目录 前言 蛇棋 1. 玩法简介 2. 实现棋子移动 前言 惭愧啊,三个月没更新下篇,问哥想起了西岳奇童...按你胃,最近确实忙得不可开交,忙着忙着,就忘记了在CSDN上继续游戏梦想了.另一方面, ...

  3. Andoird看图猜成语的小游戏

    前言 最近没什么事情,在微信上看见看图猜成语的游戏,于是自己也写了一个来玩.源码放在了文章底部. 先来看下效果图 Gif的画质就将就这样吧 我们先来分析一下 我们主要的就是这3个地方 1.就是一个im ...

  4. jQuery手机端看图猜成语小游戏代码

    下载地址 jQuery手机端看图猜成语小游戏.游戏介绍:给你一张图片,在下列文字里面选择组合一个成语,答对进入下一关游戏源码. dd:

  5. Python GUI案例之看图猜成语开发(第二篇)

    Python GUI案例之看图猜成语(第二篇) 前言 看图猜成语小程序开发(第二篇) 游戏选择模式页面 游戏训练模式页面 Python GUI案例之看图猜成语开发(第一篇) Python GUI案例之 ...

  6. Python GUI案例之看图猜成语开发(第三篇)

    Python GUI案例之看图猜成语(第三篇) 前言 看图猜成语小程序开发(第三篇) 游戏闯关模式页面 Python GUI案例之看图猜成语开发(第一篇) Python GUI案例之看图猜成语开发(第 ...

  7. 【游戏系列】用vue做个看图猜成语游戏吧

    前几年看图猜成语一类游戏风靡一时,很多人玩这个游戏,我当时也是其中之一,如今当了一个没多少头发的程序员,有时间的时候,也会去研究一下以前的那些小游戏 vue怎么创建项目这里就不介绍了,后面有时间再写一 ...

  8. python看图猜成语_看图猜成语200个图答案 看图猜成语图片答案大全

    看图猜成语2游戏v1.40苹果版 类型:ios休闲益智大小:100M语言:中文 评分:10.0 标签: 立即下载 看图猜成语200个图答案 看图猜成语图片答案大全.看图猜成语是一款很受欢迎的休闲猜谜类 ...

  9. python例程:《看图猜成语》程序

    目录 <看图猜成语>程序使用说明 主要代码展示 源码下载路径 <看图猜成语>程序使用说明 启动Idiom/flask下的venv虚拟环境,运行python manage.py ...

  10. python写游戏脚本-使用Python写一个小游戏

    引言 最近python语言大火,除了在科学计算领域python有用武之地之外,在游戏.后台等方面,python也大放异彩,本篇博文将按照正规的项目开发流程,手把手教大家写个python小游戏,来感受下 ...

最新文章

  1. 7 个漂亮的 JavaScript 的时间轴组件 [转]
  2. 第二次冲刺------第三天
  3. 通过java使用ssh访问远程Linux
  4. 大数据学习规划(新手入门)
  5. dotNET知音,19年归档
  6. 2018移动端页面适配-自适应最新方案直接写px--------通过gulp工作流搭建一体化的移动端开发环境
  7. STM32中的串口通信
  8. Internet Explorer 升级到IE11遇到问题案例分析
  9. Android NDK下载(r10~r25) 持续更新
  10. java 路径规划_应用内路径规划的简单实现
  11. R语言数据可视化案例(世界杯球员信息数据可视化)
  12. python饼状图显示其比例_Python学习笔记(matplotlib篇)--使用matplotlib绘制饼状图
  13. dxp中发光二极管在哪找_DXP2004 元件库中常用元件
  14. 将m个相同的球全部放到n个相同的盒子里面有几种放法
  15. 使用脚本配置odbc mysql_LoadRunner利用ODBC编写MySql脚本
  16. 一个JAVA学习者应该具备的素质
  17. className和classList区别
  18. 9.6 矩阵的条件数
  19. 一个大尺度超文本网络搜索引擎的剖析
  20. freebsd 启用网关

热门文章

  1. 不得不说的FUP P4K血型卡专用离心机
  2. UML用例图之寻找参与者与用例
  3. 三角形的几何公式大全_初中数学几何公式、定理梳理大全,老师都收藏了
  4. 肖申克的救赎【观影记录及经典台词摘录】
  5. 鸿蒙太空是什么意思,[评论]林黛玉:“眼泪还债”暗洒闲抛知为谁?
  6. 空调库存创新高,格力计划挖掘三四五线城市
  7. 图片怎么存储到数据库里
  8. 微信小程序-----消息模版(最全解释)
  9. 一二三代壳和加壳技术分类识别
  10. 发动机冒黑烟_汽车发动机冒黑烟什么原因,汽车发动机都可能发生哪些故障?...