骰子是很多游戏必不可少的道具,虽然用代码模拟生成骰子的点数比较简单,但在图形化的游戏里,如果能够模拟出掷骰子的效果,必然会为游戏增色不少。正好最近问哥在琢磨的几个小游戏都需要用到掷骰子,于是单独写篇文章把掷骰子这个小功能的实现方法单独拿出来。
效果
代码实现起来也比较简单,因为问哥是用python的内置模块tkinter实现的GUI,所以代码也是使用tkinter编写。
代码实现
from tkinter import *
import random
root = Tk()
root.geometry('200x250')
root.title('掷骰子')
dice_rotate = [PhotoImage(file=r'images\donghua.gif', format=f'gif -index {i}') for i in range(13)]
dice = [PhotoImage(file=f'images/{i}.png') for i in range(1,7)]
i = 0
def rotate():
global i
if i<13:
cv.itemconfig(image1,image=dice_rotate[i])
i += 1
root.after(50,rotate)
else:
cv.itemconfig(image1,image=dice[random.randint(0,5)])
i = 0
cv = Canvas(root, bg='white')
img = PhotoImage(file=r'images\1.png')
image1 = cv.create_image(100,100,image=img)
btn = Button(root, text='掷骰子',command=rotate)
cv.create_window(100,200,window=btn)
cv.pack()
root.mainloop()
解析
实现的难点主要在于如何在tkinter上播放GIF动画。
我们都知道GIF其实是一帧一帧的静态图片组合在一起,然后按照一定的播放速度展现,就变成了人肉眼看到的动画。但是使用tkinter的PhotoImage方法导入的图片,只能是某一帧的静态图片。于是我们要使用index属性调用GIF里的每一帧图片,然后再按一定的速度重复调用程序。
首先,找到我们要播放的GIF图片,比如本例中的掷骰子的GIF,通过编辑软件,可以看到它其实是由13张静态图片组成,图片的索引从0开始,从0到12.
所以我们可以先用推导式创建一个列表,用来保存每一帧的静态图片:
dice_rotate = [PhotoImage(file=r'images\donghua.gif', format=f'gif -index {i}') for i in range(13)]
如何在tkinter上创建画布Canvas和按钮Button这里就不多说了,可以参考问哥之前的文章。
既然我们想要实现按下按钮骰子自动旋转,就必须创建一个回调函数,然后绑在Button上。在这个回调函数rotate()里,我们要按顺序把13张GIF的静态图片播放完,然后随机展示骰子1到6的图片,表示骰子停下后的点数。
我们使用计数器和root.after()函数来实现GIF的顺序播放。root.after(50, rotate)函数里的两个参数,第一个表示50毫秒,第二个表示rotate函数。这句代码的意思就是设定50毫秒后再执行一次rotate函数(不是递归)。于是我们再定义一个全局变量 i 作为计数器,从0开始。每次运行rotate的时候,检查i是不是小于13,因为我们只有0到12这13张静态图片。然后在展现图片的同时,计数器累加。rotate执行13遍,也就是把GIF所有图片展示完成后,i >=12,就不再运行after函数,而是展现一张静态的骰子图片,用来表示掷骰子的结果,最后把计数器归零。
i = 0
def rotate():
global i # 全局变量计数器
if i<12:
cv.itemconfig(image1,image=dice_rotate[i]) # 循环“播放”GIF的图片
i += 1
root.after(50,rotate) # 50毫秒后再执行一次rotate函数
else:
cv.itemconfig(image1,image=dice[random.randint(0,5)]) # 掷骰子的结果
i = 0 # 计数器归零
当然,最后需要展示一张骰子的静图,表示掷骰子的结果,1到6的骰子静图在一开始就定义另在一个图片列表里了。
dice = [PhotoImage(file=f'images/{i}.png') for i in range(1,7)]
所以程序的最后只需要使用一个随机数生成0到5的数字,代表图片在列表中的序列。
如此,便可以实现在tkinter上掷骰子的效果了。