【上期回顾:Tkinter模块GUI界面化编程实战(五)——大鱼吃小鱼游戏】
这篇博客介绍了如何用Python Tkinter模块编写一个界面化的超级游戏盒子,在博客下面有完整的源码,源码中有详细的注释,帮助大家理解代码(最后还有附件可以免费下载)
【注:下载文件100%可以运行,因为下载文件中包含打包了的Python程序(exe文件)!】
用Tkinter模块编写一个超级游戏盒子
【话不多说,视频如下】
各位观众老爷,怎么样?若觉得可以,请在评论区发一个“666”,若不行请发一个“就这”
【注:本人大一学生一个,初学Python而已[doge],能力有限】
这里面的游戏可以放7个,但是我只写了2个,还有的5个只是写了个名称(打了个感叹号),没有真正的功能[doge]。
下面就让我来手把手教你如何写一个这样的玩意儿!(完整源码在底下)
【废话少说,直接教学】
【程序功能描述】
①有个加载页面(也相当于欢迎页面),用来读取主页面的背景图片(gif格式)的每一帧
②主页面上有3个按钮,分别是“设置”“开始”“退出”,功能就是字面意思
③点击前两个按钮,会弹出来一个新的“对话框”(不是真的对话框,只是画出来的)
④主页面可以随意拖动,没有窗口框
⑤游戏部分很简单,就是一个游戏写成一个类,到时候直接拿来用就行(做好兼容)
⑥设置页里有“语言”、“刷新率”、“透明度”、“字体”、“音乐”这5个选项,其实还有个帮助
⑦语言选项不仅要改变主页面语言,游戏里的语言也要改变
⑧那几个游戏的事哈,我在前几期就已经写了怎么弄了,不知道的,可以看看这个链接:
【主体框架】
每个游戏由一个类构成,完成这个游戏的所有功能,各个游戏(类)之间不会相互影响,然后由组成主体代码的游戏盒子去调用它们就可以实现游戏盒子的功能了。
关于视频中游戏盒子里的两个游戏,下面将不会赘述,可以参见以下链接:
2048小游戏:点我传送!
大鱼吃小鱼游戏:点我传送!
【编写思路图】
【注:最后一步,添加音乐是由pygame模块完成的】
1st 搭建窗口框架
【Line7&Line315~Line324&Line353~Line358】
起初的设想里面本来是没有那个有进度条的欢迎页面的,只有主页面,主页面的排版如下
后来由于某些原因(见2nd),加上了欢迎页面,加载进度条的欢迎页面排版如下
注:这里的白色不完全是白色,其RGB码为F0F0F0(这是Tkinter模块默认的背景颜色)
或许这些东西由Canvas控件去实现更加的规范,但是我为了简单和方便,就直接用Label控件了
2nd 加载背景图片
【Line341&Line332~Line336】
主页面用一个有逼格的gif图片来作为背景,由于Tkinter模块中直接读取gif图片只会读取到图片第一帧的画面,所以要用特殊的方法来加载这个图片(加载gif动图的关键部分如下)
frames += [PhotoImage(file='resources\\GIF.gif',format='gif -index %i'%(i//12.5))]#加载每一帧图片
每一帧都执行这个代码,对于40帧的gif动图,要执行40次
而加载是需要时间的(我这个gif图片的总帧数为40),如果这个时候程序不做点其他啥事的话,这段时间内程序的界面会处于一种类似“未响应”的状态(感觉就很卡,不流畅),所以我就用一个进度条加载的方式来显示加载的进度(这个灵感主要来自《我的世界》的加载页面),以此来避免这种情况。所以说,那个进度条是用来显示背景图片加载的进度。
背景图片的更新(可以设定更新每一帧的速度,s_gif为更新每一帧间隔的时间,单位ms)
def update(idx):
frame = frames[idx]
idx += 1
imagelabel.config(image=frame)
game.after(s_gif,update,idx%numIdx)#gif图片定时器函数
3rd 编写欢迎页面
【Line322~Line324&Line328】
下面的代码是欢迎页面的页面框架(还没有添加进度条,只有进度条的框框)
Label(f01,text='- WELCOME -',font=(s_font,100)).place(width=960,height=400)#欢迎页面标签
Label(f01,bg='black').place(width=504,height=25,y=360,x=228)#进度条外框
Label(f01).place(width=500,height=21,y=362,x=230)#进度条内部
进度的实现是通过每次执行2nd中所提到的代码的同时把那个橙色Label的长度给改一下(同步修改)
barlabel = Label(f01,bg='orange')
def update(idx):
frame = frames[idx]
idx += 1
imagelabel.config(image=frame)
game.after(s_gif,update,idx%numIdx)#gif图片定时器函数
def load():#加载函数
global i,frames
if i < 500:
frames += [PhotoImage(file='resources\\GIF.gif',format='gif -index %i'%(i//12.5))]#加载每一帧图片
barlabel.place(width=i+12.5,height=21,y=362,x=230)
game.after(1,load)#进度条显示
else:
pygame.mixer.music.play(loops=10)#播放音乐
imagelabel.place(width=960,height=480)#gif图片放置
game.after(0,update,0)#gif图片显示
homepage()
f01.destroy()#加载主页、摧毁欢迎页
i += 12.5#进度条每次增加12.5
先别管那个播放音乐,后面去添加就行
4th 设定主页按钮
【Line352~Line372】
主页面的按钮很简单,就是直接用Button控件,然后给它加个事件绑定,使得我们的鼠标移过它们的时候,它们会改变一下样式就行,代码如下
def enter(event):event.widget['fg']='yellow';event.widget['bg']='dimgray'
def leave(event):event.widget['fg']='orange';event.widget['bg']='black'
def homepage():#主页面
b01 = Button(game,bg='black',bd=0,font=(s_font,15),fg='orange',text=language[0],command=setpage)
b01.place(width=100,height=30,x=310,y=400)#设置按钮
b02 = Button(game,bg='black',bd=0,font=(s_font,15),fg='orange',text=language[1],command=playselect)
b02.place(width=100,height=30,x=430,y=400)#开始按钮
b03 = Button(game,bg='black',bd=0,font=(s_font,15),fg='orange',text=language[2],command=game.quit)
b03.place(width=100,height=30,x=550,y=400)#退出按钮
for i in [b01,b02,b03]:
i.bind('<Enter>',enter)
i.bind('<Leave>',leave)#按钮关联鼠标进入事件
def move(event):
global selfx,selfy
game.geometry(size+'+%s+%s'%(game.winfo_x()+event.x-selfx,game.winfo_y()+event.y-selfy))#窗口移动函数
def beforemove(event):
global selfx,selfy
selfx,selfy=event.x,event.y
game.bind('<B1-Motion>',lambda event:move(event))#鼠标左键一直按下移动事件关联
game.bind('<Button-1>',lambda event:beforemove(event))#鼠标左键按下移动事件关联
代码中有个部分是用来实现窗口随意拖动的(move函数、beforemove函数、底下的两个bind)
那个实现窗口的拖动的方法,大家看看就行,对于每个Tkinter程序应该都适用。有一些变量我没给出来,请大家到下面的源码中去找吧。
5th 编写设置按钮
【Line374~Line401】
这个设置页面(下面的游戏选择页面也是一样的)的基本思想就是画一个“对话框”出来,而不是直接用Tkinter模块内部提供的对话框产生方式。这个对话框与内部提供的对话框是不一样的,这个对话框不能移动,因为它是画出来的(用Label控件比较方便),虽然不能移动,但是它的样式我们可以随意控制。
下面是那个设置页面的主体版式的代码(功能实现代码见6th)
def setpage():#设置页面
f31 = Frame(game,bg='lightyellow')
f31.place(width=600,height=340,x=180,y=60)#设置页框架
Label(f31,font=(s_font,15),text=language[3],anchor='w',bg='grey').place(width=600,height=30)#设置页头部
Label(f31,bg='grey').place(width=600,height=40,y=300)#设置页底部
b31 = Button(f31,font=(s_font,15),text='×',bg='grey',bd=0,command=f31.destroy)
b31.place(width=30,height=30,x=570)#关闭按钮
b32 = Button(f31,font=(s_font,15),text='?',bg='grey',bd=0,command=lambda:sethelp())
b32.place(width=30,height=30,x=540)#帮助按钮
b33 = Button(f31,font=(s_font,15),bd=0,bg='lightgreen',text=language[10],command=lambda:okget())
b33.place(width=100,height=30,y=305,x=380)#确定按钮
b34 = Button(f31,font=(s_font,15),bd=0,bg='lightgreen',text=language[11],command=f31.destroy)
b34.place(width=100,height=30,y=305,x=490)#取消按钮
for i in range(5,10):Label(f31,font=(s_font,20),bg='lightyellow',text=language[i]).place(width=200,height=40,x=100,y=(i-4)*50)#各个设置项
e31 = Entry(f31,font=(s_font,20),bg='lightyellow',textvariable=s_1,bd=0,justify='center')
e31.place(width=150,height=40,x=350,y=50)#刷新率文本框
e32 = Entry(f31,font=(s_font,20),bg='lightyellow',textvariable=s_2,bd=0,justify='center')
e32.place(width=150,height=40,x=350,y=100)#透明度文本框
e33 = Entry(f31,font=(s_font,20),bg='lightyellow',textvariable=s_3,bd=0,justify='center')
e33.place(width=150,height=40,x=350,y=150)#字体文本框
b35 = Button(f31,font=(s_font,20),bg='lightyellow',textvariable=s_4,bd=0,command=lambda:cmd4())
b35.place(width=150,height=40,x=350,y=200)#语言切换
b36 = Button(f31,font=(s_font,20),bg='lightyellow',textvariable=s_5,bd=0,command=lambda:cmd5())
b36.place(width=150,height=40,x=350,y=250)#音乐开关
效果如下
在界面的右上角有个小问号,点击就是帮助页面,其代码如下(帮助页面的内容见6th)
def sethelp():#帮助页面
fhelp = Frame(f31)
fhelp.place(width=400,height=250,x=100,y=40)#帮助框架
Label(fhelp,bg='gray',font=(s_font,15),text=language[15]).place(width=400,height=30)#帮助页面头部
Label(fhelp,bg='gray',font=(s_font,15)).place(width=400,height=30,y=220)#帮助页面底部
Label(fhelp,text=language[17],font=(s_font,15)).place(width=400,height=190,y=30)#帮助主体内容
b37 = Button(fhelp,text=language[10],bd=0,bg='lightgreen',font=(s_font,12),command=fhelp.destroy)
b37.place(width=80,height=20,y=225,x=315)#确定按钮
b38 = Button(fhelp,text=language[16],bd=0,bg='lightgreen',font=(s_font,12),command=lambda:restoredefault())
b38.place(width=120,height=20,y=225,x=5)#默认设置按钮
实现后的效果就是这样的
6th 实现设置选项
【Line8~Line29&Line374~Line475】
设置页面选项的实现比较复杂,有一点点多,不过我的注释应该写得很清楚了,有不懂的可以在评论区说一下
其实那个语言的切换很简单,我早就把双语的内容都写好了(弄成了列表),只需要切换一下就行
程序中有很多按钮的事件绑定,那些事件绑定的函数我都写在了【Line31~Line39】
###################################### 可设置的默认变量 ######################################
# 语言变量 #
Englishfont = ['Set','Play','Quit','System Set','Select Game','Refresh Rate','Transparency','Font','Language','Music','OK','Cancel','None','On','Off','Help','Restore Default',\
'Refresh rate is the refresh rate\nof the background picture\nTransparency is the transparency\nof the game window\n\n1ms≤Refresh rate≤1000ms\n0<Transparency≤1','Again',\
"Press 'w' , 's' , 'a' and 'd' to move!\n4000 points win!\nGood luck!"]
Chinesefont = ['设置','开始','退出','系统设置','选择游戏','刷新率','透明度','字体','语言','音乐','确定','取消','暂无','开','关','帮助','恢复默认',\
'刷新率是背景图片的刷新速度\n透明度是游戏窗口的透明程度\n\n1ms≤刷新率≤1000ms\n0<透明度≤1','重置',\
'按‘w’、‘s’、‘a’和‘d’进行移动!\n4000分胜利!\n祝你好运!']
language = Englishfont#长度为20
# 特殊变量 #
s_gif = 10 #gif图刷新速度
s_alpha = 1 #窗口透明度
s_font = '华文新魏' #字体
s_language = 'English' #语言
s_audio = language[13] #声音
# 系统变量 #
(s_1 := StringVar()).set(s_gif)
(s_2 := StringVar()).set(s_alpha)
(s_3 := StringVar()).set(s_font)
(s_4 := StringVar()).set(s_language)
(s_5 := StringVar()).set(s_audio)
def setpage():#设置页面
f31 = Frame(game,bg='lightyellow')
f31.place(width=600,height=340,x=180,y=60)#设置页框架
Label(f31,font=(s_font,15),text=language[3],anchor='w',bg='grey').place(width=600,height=30)#设置页头部
Label(f31,bg='grey').place(width=600,height=40,y=300)#设置页底部
b31 = Button(f31,font=(s_font,15),text='×',bg='grey',bd=0,command=f31.destroy)
b31.place(width=30,height=30,x=570)#关闭按钮
b32 = Button(f31,font=(s_font,15),text='?',bg='grey',bd=0,command=lambda:sethelp())
b32.place(width=30,height=30,x=540)#帮助按钮
b33 = Button(f31,font=(s_font,15),bd=0,bg='lightgreen',text=language[10],command=lambda:okget())
b33.place(width=100,height=30,y=305,x=380)#确定按钮
b34 = Button(f31,font=(s_font,15),bd=0,bg='lightgreen',text=language[11],command=f31.destroy)
b34.place(width=100,height=30,y=305,x=490)#取消按钮
for i in range(5,10):Label(f31,font=(s_font,20),bg='lightyellow',text=language[i]).place(width=200,height=40,x=100,y=(i-4)*50)#各个设置项
e31 = Entry(f31,font=(s_font,20),bg='lightyellow',textvariable=s_1,bd=0,justify='center')
e31.place(width=150,height=40,x=350,y=50)#刷新率文本框
e32 = Entry(f31,font=(s_font,20),bg='lightyellow',textvariable=s_2,bd=0,justify='center')
e32.place(width=150,height=40,x=350,y=100)#透明度文本框
e33 = Entry(f31,font=(s_font,20),bg='lightyellow',textvariable=s_3,bd=0,justify='center')
e33.place(width=150,height=40,x=350,y=150)#字体文本框
b35 = Button(f31,font=(s_font,20),bg='lightyellow',textvariable=s_4,bd=0,command=lambda:cmd4())
b35.place(width=150,height=40,x=350,y=200)#语言切换
b36 = Button(f31,font=(s_font,20),bg='lightyellow',textvariable=s_5,bd=0,command=lambda:cmd5())
b36.place(width=150,height=40,x=350,y=250)#音乐开关
def cmd4():
global s_language
s_language = 'English' if s_language=='简体中文' else '简体中文'
s_4.set(s_language)#语言切换函数
def cmd5():
global s_audio
s_audio = 'On' if s_audio=='Off' else 'Off' if s_audio=='On' else '开' if s_audio=='关' else '关'
s_5.set(s_audio)#音乐开关函数
b31.bind('<Enter>',shutenter)
b31.bind('<Leave>',shutleave)#按钮关联鼠标进入事件
b32.bind('<Enter>',helpenter)
b32.bind('<Leave>',shutleave)#按钮关联鼠标进入事件
for i in [e31,e32,e33,b35,b36]:
i.bind('<Enter>',enter2)
i.bind('<Leave>',leave2)#按钮关联鼠标进入事件
for i in [b33,b34]:
i.bind('<Enter>',enter3)
i.bind('<Leave>',leave3)#按钮关联鼠标进入事件
def sethelp():#帮助页面
fhelp = Frame(f31)
fhelp.place(width=400,height=250,x=100,y=40)#帮助框架
Label(fhelp,bg='gray',font=(s_font,15),text=language[15]).place(width=400,height=30)#帮助页面头部
Label(fhelp,bg='gray',font=(s_font,15)).place(width=400,height=30,y=220)#帮助页面底部
Label(fhelp,text=language[17],font=(s_font,15)).place(width=400,height=190,y=30)#帮助主体内容
b37 = Button(fhelp,text=language[10],bd=0,bg='lightgreen',font=(s_font,12),command=fhelp.destroy)
b37.place(width=80,height=20,y=225,x=315)#确定按钮
b38 = Button(fhelp,text=language[16],bd=0,bg='lightgreen',font=(s_font,12),command=lambda:restoredefault())
b38.place(width=120,height=20,y=225,x=5)#默认设置按钮
for i in [b37,b38]:
i.bind('<Enter>',enter3)
i.bind('<Leave>',leave3)#按钮关联鼠标进入事件
def restoredefault():#默认设置函数
global s_gif,s_alpha,s_font,s_language,s_audio,language
s_1.set(s_gif:=10)
s_2.set(s_alpha:=1)
s_3.set(s_font:='华文新魏')
s_4.set(s_language:='English');language = Englishfont
s_5.set(s_audio:=language[13])
fhelp.destroy()#关闭帮助页面
def okget():#设置改变函数
global s_gif,s_alpha,s_font,s_language,s_audio,language
f31.destroy()
if 0<float(s_1.get())<=1000:
s_gif = s_1.get()#设置刷新率
else:
s_1.set(s_gif:=10)#切换为默认值
if 0<float(s_2.get())<=1:
s_alpha = s_2.get()#设置透明度
else:
s_2.set(s_alpha:=1)#切换为默认值
s_font = s_3.get()#字体切换
language = Englishfont if s_language == 'English' else Chinesefont#语言切换
if s_audio == 'On' or s_audio == '开':
s_5.set(s_audio:=language[13])
pygame.mixer.music.unpause()#音乐继续播放
if not pygame.mixer.music.get_busy():pygame.mixer.music.play(loops=10)
else:
s_5.set(s_audio:=language[14])
pygame.mixer.music.pause()#音乐暂停
game.wm_attributes("-alpha",s_alpha)
homepage()#改变系统变量并重新加载
对于音乐的开关,我们暂且不管哈
7th 编写开始按钮
【Line477~Line506】
点击开始按钮后会弹出游戏选择界面,这个界面的实现原理与设置页面类似,这里就不再赘述
代码如下
def playselect():#开始页面
f11 = Frame(game,bg='lightyellow')
f11.place(width=200,height=340,x=380,y=60)#开始页面框架
Label(f11,font=(s_font,15),text=language[4],anchor='w',bg='grey').place(width=200,height=30)#开始页面头部
b11 = Button(f11,font=(s_font,15),text='×',bg='grey',bd=0,command=f11.destroy)
b11.place(width=30,height=30,x=170)#关闭按钮
for i in range(len(lis:=[Button(f11)]*7)):
lis[i]=Button(f11,bg='lightyellow',font=(s_font,15),bd=0,text=gamelist[i],command=lambda arg=i:gamestart(arg+1))
lis[i].place(width=180,height=30,x=10,y=i*40+50)
b11.bind('<Enter>',shutenter)
b11.bind('<Leave>',shutleave)#按钮关联鼠标进入事件
for i in lis:
i.bind('<Enter>',enter2)
i.bind('<Leave>',leave2)#按钮关联鼠标进入事件
def gamestart(n):
pygame.mixer.music.stop()
f11.destroy()
if n == 1:Game1()
elif n == 2:Game2()
elif n == 3:Game3()
elif n == 4:Game4()
elif n == 5:Game5()
elif n == 6:Game6()
else:None
效果如图
8th 调用游戏类
在7th的代码里,有个gamestart函数,那个就是调用游戏类的函数,每个游戏都写成一个类,由这个函数去调用。游戏的类在【Line50~Line313】,目前我只弄了两个游戏,这里就不再详述怎么实现的了,可以参见下面的链接
2048小游戏:点我传送!
大鱼吃小鱼游戏:点我传送!
这里唯一要注意的就是要做好游戏类与游戏盒子的对接问题(如语言和音乐)
9th 实现退出功能
这个应该是最简单的了吧,为了美观,之前在制作页面的时候,是隐藏了窗口框架了的,所以没有我们平时看到的“最大化”、“最小化”和“关闭”按钮,于是关闭窗口并结束程序的功能就需要我们自己去实现。主页面的关闭由“退出”按钮实现,功能简单,这里不再赘述,且看源码就行。还有其他的关闭按钮,如设置页面和游戏选择页面右上角的关闭,都需要我们自己来制作。其实一些“取消”按钮也有关闭的功能。
10th 添加音乐
因为Tkinter模块好像无法实现音频的播放,无奈之下的我只好稍微了解了一下pygame模块,然后知道了只需要用一点点代码就可以实现音乐的播放了
import pygame
pygame.mixer.init()
pygame.mixer.music.load('resources\\Rise.wav')#加载音乐
pygame.mixer.music.play(loops=10)#音乐播放,loop参数为循环次数
pygame.mixer.music.stop()#音乐终止播放
pygame.mixer.music.pause()#音乐暂停播放
pygame.mixer.music.unpause()#音乐继续播放
其实还可以实现小音频的播放,比较简单,但这里就不说了
【多说无益,且看源码】
注意哦,这个源码直接复制粘贴是不能运行的,因为有那个背景图片和音乐要读取,你可以下载博客底下的附件(免费的),那里面有完整的程序及资源文件,还有已打包好的exe可执行文件!
from tkinter import *
from random import *
import pygame
################################################################################################################
pygame.mixer.init()
pygame.mixer.music.load('resources\\Rise.wav')#加载音乐
game = Tk()#创建窗口
###################################### 可设置的默认变量 ######################################
# 语言变量 #
Englishfont = ['Set','Play','Quit','System Set','Select Game','Refresh Rate','Transparency','Font','Language','Music','OK','Cancel','None','On','Off','Help','Restore Default',\
'Refresh rate is the refresh rate\nof the background picture\nTransparency is the transparency\nof the game window\n\n1ms≤Refresh rate≤1000ms\n0<Transparency≤1','Again',\
"Press 'w' , 's' , 'a' and 'd' to move!\n4000 points win!\nGood luck!"]
Chinesefont = ['设置','开始','退出','系统设置','选择游戏','刷新率','透明度','字体','语言','音乐','确定','取消','暂无','开','关','帮助','恢复默认',\
'刷新率是背景图片的刷新速度\n透明度是游戏窗口的透明程度\n\n1ms≤刷新率≤1000ms\n0<透明度≤1','重置',\
'按‘w’、‘s’、‘a’和‘d’进行移动!\n4000分胜利!\n祝你好运!']
language = Englishfont#长度为20
# 特殊变量 #
s_gif = 10 #gif图刷新速度
s_alpha = 1 #窗口透明度
s_font = '华文新魏' #字体
s_language = 'English' #语言
s_audio = language[13] #声音
# 系统变量 #
(s_1 := StringVar()).set(s_gif)
(s_2 := StringVar()).set(s_alpha)
(s_3 := StringVar()).set(s_font)
(s_4 := StringVar()).set(s_language)
(s_5 := StringVar()).set(s_audio)
########################################## 通用函数 ##########################################
def enter(event):event.widget['fg']='yellow';event.widget['bg']='dimgray'
def leave(event):event.widget['fg']='orange';event.widget['bg']='black'
def enter2(event):event.widget['bg']='grey';event.widget['fg']='orange'
def leave2(event):event.widget['bg']='lightyellow';event.widget['fg']='black'
def enter3(event):event.widget['bg']='springgreen'
def leave3(event):event.widget['bg']='lightgreen'
def shutenter(event):event.widget['fg']='white';event.widget['bg']='red'
def shutleave(event):event.widget['fg']='black';event.widget['bg']='grey'
def helpenter(event):event.widget['fg']='white';event.widget['bg']='lightgreen'
def GameQuit_MusicSet():
global s_audio
if s_audio == 'On' or s_audio == '开':
s_audio = language[13]
s_5.set(s_audio)
pygame.mixer.music.play(loops=10)
##############################################################################################
gamelist = ['2048小游戏','简易枪战[!]','大鱼吃小鱼','俄罗斯方块[!]','贪吃蛇[!]','飞机大战[!]',language[12]]
#################################################### 游戏代码区域 ####################################################
# 游戏1 #
def Game1():
global size
game.geometry('305x205+500+250')
game1 = Frame(game);size='305x205';game1.place(width=305,height=205)
def base():
numdict = {1:{},2:{},3:{},4:{}}
for key in numdict.keys():numdict[key] = {1:'',2:'',3:'',4:''}
while 1:
x1,x2,y1,y2 = randint(1,4),randint(1,4),randint(1,4),randint(1,4)
if x1 != x2 or y1 !=y2:numdict[x1][y1],numdict[x2][y2] = 2,2;break
Label(game1,bg='#BBADA0').place(width=205,height=205)
Label(game1,bg='orange' ).place(width=100,height=205,x=205)
Label(game1,bg='#FAF8EF' ).place(x=210,y=5,width=90,height=195)
(score := StringVar()).set('Score\n\n0');(score_value := StringVar()).set('0')
Label(game1,textvariable=score,font=(s_font,15),bg='yellow').place(x=215,y=10,width=80,height=100)
quitbutton = Button(game1,text=language[2],font=(s_font,15),bd=0,bg='lightgreen',command=lambda:game1quit());quitbutton.place(x=215,y=160,width=80,height=30)
playbutton = Button(game1,text=language[1],font=(s_font,15),bd=0,bg='lightgreen',command=lambda:gamestart());playbutton.place(x=215,y=120,width=80,height=30)
n14 = StringVar();n24 = StringVar();n34 = StringVar();n44 = StringVar()
n13 = StringVar();n23 = StringVar();n33 = StringVar();n43 = StringVar()
n12 = StringVar();n22 = StringVar();n32 = StringVar();n42 = StringVar()
n11 = StringVar();n21 = StringVar();n31 = StringVar();n41 = StringVar()
for sy in [5,55,105,155]:#放置格子
for sx,i in zip([5,55,105,155],[n14,n24,n34,n44,n13,n23,n33,n43,n12,n22,n32,n42,n11,n21,n31,n41][4*(sy-5)//50:4*(sy+45)//50]):
Label(game1,bg='#CDC1B4',textvariable=i,font=(s_font,15)).place(width=45,height=45,y=sy,x=sx)
def initialization():#初始化
for x in range(1,5):
for y,i in zip(range(1,5),[n11,n12,n13,n14,n21,n22,n23,n24,n31,n32,n33,n34,n41,n42,n43,n44][4*(x-1):4*x]):i.set(numdict[x][y])
def gamewin(score=0):#游戏胜利
for value in numdict.values():
for i in value.values():
if str(i).isdigit():score+=int(i)
if score>=2048:
frame_win = Frame(game1,bg='yellow');frame_win.place(width=305,height=205)
Label(frame_win,text='You Win!',font=(s_font,30),fg='red',bg='yellow').place(width=305,height=60)
Button(frame_win,bd=0,bg='lightgreen',font=(s_font,15),text=language[18],command=lambda:base()).place(width=80,height=30,y=150,x=45)
Button(frame_win,bd=0,bg='lightgreen',font=(s_font,15),text=language[2],command=lambda:game1quit()).place(width=80,height=30,y=150,x=180)
Label(frame_win,font=(s_font,15),text='You have got to\n2048!',bg='yellow').place(width=205,height=60,y=60,x=50)
else:game1.after(100,gamewin)
def gameover():#游戏结束
frame_over = Frame(game1,bg='yellow');frame_over.place(width=305,height=205)
Label(frame_over,text='Game Over!',font=(s_font,30),fg='red',bg='yellow').place(width=305,height=60)
Button(frame_over,bd=0,bg='lightgreen',font=(s_font,15),text=language[18],command=lambda:base()).place(width=80,height=30,y=150,x=45)
Button(frame_over,bd=0,bg='lightgreen',font=(s_font,15),text=language[2],command=lambda:game1quit()).place(width=80,height=30,y=150,x=180)
Label(frame_over,font=(s_font,50),textvariable=score_value,bg='yellow').place(width=205,height=60,y=60,x=50)
def move(way,count=0):#操作函数
if way in ['w','s','a','d']:#判断是否为正确的操作
if way == 'w':
for x in range(1,5):
numdict[x][5] = 0
for y in range(1,5):
if numdict[x][y] == numdict[x][y+1] and numdict[x][y] != '':numdict[x][y] = '';numdict[x][y+1] *= 2
elif numdict[x][y] != '' and numdict[x][y+1] == '':numdict[x][y],numdict[x][y+1]=numdict[x][y+1],numdict[x][y]
del numdict[x][5]
if way == 's':
for x in range(1,5):
numdict[x][0] = 0
for y in range(4,0,-1):
if numdict[x][y] == numdict[x][y-1] and numdict[x][y] != '':numdict[x][y] = '';numdict[x][y-1] *= 2
elif numdict[x][y] != '' and numdict[x][y-1] == '':numdict[x][y],numdict[x][y-1]=numdict[x][y-1],numdict[x][y]
del numdict[x][0]
if way == 'd':
numdict[5] = {1:0,2:0,3:0,4:0}
for y in range(1,5):
for x in range(1,5):
if numdict[x][y] == numdict[x+1][y] and numdict[x][y] != '':numdict[x][y] = '';numdict[x+1][y] *= 2
elif numdict[x][y] != '' and numdict[x+1][y] == '':numdict[x][y],numdict[x+1][y]=numdict[x+1][y],numdict[x][y]
del numdict[5]
if way == 'a':
numdict[0] = {1:0,2:0,3:0,4:0}
for y in range(1,5):
for x in range(4,0,-1):
if numdict[x][y] == numdict[x-1][y] and numdict[x][y] != '':numdict[x][y] = '';numdict[x-1][y] *= 2
elif numdict[x][y] != '' and numdict[x-1][y] == '':numdict[x][y],numdict[x-1][y]=numdict[x-1][y],numdict[x][y]
del numdict[0]
for x in range(1,5):
for y,i in zip(range(1,5),[n11,n12,n13,n14,n21,n22,n23,n24,n31,n32,n33,n34,n41,n42,n43,n44][4*(x-1):4*x]):
i.set(numdict[x][y])
if numdict[x][y] == '':count = 1
if count == 0:gameover();return None#决定是否结束游戏
while 1:#随机再产生一个数
x,y = randint(1,4),randint(1,4)
if numdict[x][y] == '':numdict[x][y] = choice([2,4]);break
[n11,n12,n13,n14,n21,n22,n23,n24,n31,n32,n33,n34,n41,n42,n43,n44][4*x+y-5].set(numdict[x][y])
def scorevalue(value=0):#计分板
for x in range(1,5):
for y in range(1,5):
if numdict[x][y] != '':value += numdict[x][y]
score.set('Score\n\n%s'%value);score_value.set(str(value));game1.after(10,scorevalue)
def gamestart():#游戏开始
game.bind('<Any-KeyPress>',lambda event:move(event.char))#键盘关联
initialization()#初始化
scorevalue()#开始计分
gamewin()#检测胜利
def enter(event):event.widget['bg']='springgreen'
def leave(event):event.widget['bg']='lightgreen'
for i in [quitbutton,playbutton]:
i.bind('<Enter>',lambda event:enter(event));i.bind('<Leave>',lambda event:leave(event))
def game1quit():global size;game.unbind('<Any-KeyPress>');game1.destroy();size='960x480';game.geometry('960x480+150+100');GameQuit_MusicSet()
base()
# 游戏2 #
class Game2():pass
# 游戏3 #
###############################
class Game3:
def __init__(self):
self.pw,self.ph,self.px,self.py=40,20,455,250
self.pf=15
self.count=0
self.god=False
self.score=0
self.RGBcolorlist = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
self.Score=IntVar()
self.Score.set(self.score)
self.game3 = Frame(game)
self.game3.place(width=960,height=480)
self.main = Frame(self.game3)
self.main.place(width=960,height=480)
self.player = Label(self.game3,bg='black',fg='white',font=('consolas',self.pf),text='O',anchor='w')
self.player.place(width=self.pw,height=self.ph,y=self.py,x=self.px)
Label(self.game3,bg='lightgreen',textvariable=self.Score,font=(s_font,20)).place(width=960,height=40)
for i in range(3):Label(self.game3,bg='red').place(width=30,height=30,y=5,x=925-35*i)
self.life = Label(self.game3,bg='lightgreen')
self.life.place(height=40,x=845,width=0)
Button(self.game3,bd=0,bg='orange',text=language[2],font=(s_font,15),command=lambda:self.fishquit()).place(width=100,height=30,y=5,x=5)#退出按钮
Button(self.game3,bd=0,bg='orange',text=language[18],font=(s_font,15),command=lambda:self.fishagain()).place(width=100,height=30,y=5,x=110)#重置按钮
self.game3start()
def game3start(self):
game3help = Frame(self.game3)
game3help.place(width=600,height=360,y=60,x=180)
Label(game3help,text=language[15],bg='grey',font=(s_font,15)).place(width=600,height=30)
Label(game3help,bg='lightgreen',font=(s_font,20),text=language[19]).place(width=600,height=300,y=30)
Label(game3help,bg='grey').place(width=600,height=30,y=330)
Button(game3help,bg='lightgreen',text=language[10],bd=0,font=(s_font,12),command=lambda:start()).place(width=80,height=20,y=335,x=510)
def start():
game.bind('<Any-KeyPress>',lambda event:self.playmove(event.char))#键盘关联
self.randomfish()
game3help.destroy()
def fishagain(self):
self.pw,self.ph,self.px,self.py=40,20,455,250
self.pf=15
self.count=0
self.score=0
self.game3.destroy()
Game3()#重置函数
def fishquit(self):
global s_audio
game.unbind('<Any-KeyPress>')
self.game3.destroy()
GameQuit_MusicSet()#退出函数
def victory(self):#胜利设定
if self.score >= 4000:
Label(self.game3,bg='lightyellow',font=(s_font,100),text='- Victory -',fg='orange').place(width=960,height=440,y=40)
self.main.destroy()
def death(self):#死亡设定
self.count+=1
if self.count <3:
self.god = True if self.god == False else False
self.life.place(height=40,x=845,width=self.count*40)
else:
self.life.place(height=40,x=845,width=120)
self.main.destroy()
Label(self.game3,bg='lightyellow',font=(s_font,100),text='- You Dead -',fg='orange').place(width=960,height=440,y=40)
if self.god == True:
self.count-=1
self.game3.after(1000,self.death)
def eattest(self,fish,rw,rh,ry,rx):#碰撞检测
if self.god == False:
pxw = self.px+self.pw
pyh = self.py+self.ph
rxw = rx+rw
ryh = ry+rh
test = True if (self.px<rx<pxw or self.px<rxw<pxw or rx<self.px<rxw or rx<pxw<rxw) and (self.py<ry<pyh or self.py<ryh<pyh or ry<self.py<ryh or ry<pyh<ryh) else False
if test == True:
if self.pw*self.ph > rw*rh:
fish.destroy()
self.score+=rw+rh
self.Score.set(self.score)
self.pw=self.score//40+40
self.ph=self.score//80+20
self.pf=self.score//100+15
self.player.config(font=('consolas',self.pf))
self.victory()
else:
self.death()
def fishmove(self,fish,speed,rway,rw,rh,ry,rx):#鱼的移动
rx += speed if rway == 'e' else -1*speed
fish.place(width=rw,height=rh,y=ry,x=rx)
self.eattest(fish,rw,rh,ry,rx)
if rx >960 or rx+rw <0:fish.destroy()
else:self.main.after(10,self.fishmove,fish,speed,rway,rw,rh,ry,rx)
def randomfish(self,rcolor='#'):#随机刷新鱼
for _ in range(6):rcolor+=choice(self.RGBcolorlist)
speed = randint(10,100+self.score//100)*0.01
rway = choice(['w','e'])
rh = randint(self.ph//4,self.ph*2)
while 1:
rw = randint(self.pw//4,self.pw*2)
if rw > 1.2*rh:break
rx = -1*rw if rway == 'e' else 960
ry = randint(40,480-rh)
rf = rh//2
fish = Label(self.main,bg=rcolor,font=('consolas',rf),text='O',anchor=rway)
fish.place(width=rw,height=rh,y=ry,x=rx)
self.fishmove(fish,speed,rway,rw,rh,ry,rx)
self.main.after(randint(1000,3000),self.randomfish)
def playmove(self,way):#玩家移动
if way == 'w' and self.py>40:
self.py-=10
elif way == 's' and self.py<=470-self.ph:
self.py+=10
elif way == 'a' and self.px>0:
self.px-=10
self.player.config(anchor='w')
elif way == 'd' and self.px<=955-self.pw:
self.px+=10
self.player.config(anchor='e')
self.player.place(width=self.pw,height=self.ph,y=self.py,x=self.px)
class Game4():pass
class Game5():pass
class Game6():pass
#####################################################################################################################
game.geometry('960x480+150+100')
game.resizable(0,0)
game.overrideredirect(1)#设置窗口基本属性
f01 = Frame(game)
f01.place(width=960,height=480)#欢迎框架
Label(f01,text='- WELCOME -',font=(s_font,100)).place(width=960,height=400)#欢迎页面标签
Label(f01,bg='black').place(width=504,height=25,y=360,x=228)#进度条外框
Label(f01).place(width=500,height=21,y=362,x=230)#进度条内部
numIdx,i,frames = 40,0,[]
imagelabel = Label(game,bg='black')
barlabel = Label(f01,bg='orange')
selfx,selfy=0,0
size = '960x480'#定义一些必要变量
def update(idx):
frame = frames[idx]
idx += 1
imagelabel.config(image=frame)
game.after(s_gif,update,idx%numIdx)#gif图片定时器函数
def load():#加载函数
global i,frames
if i < 500:
frames += [PhotoImage(file='resources\\GIF.gif',format='gif -index %i'%(i//12.5))]#加载每一帧图片
barlabel.place(width=i+12.5,height=21,y=362,x=230)
game.after(1,load)#进度条显示
else:
pygame.mixer.music.play(loops=10)#播放音乐
imagelabel.place(width=960,height=480)#gif图片放置
game.after(0,update,0)#gif图片显示
homepage()
f01.destroy()#加载主页、摧毁欢迎页
i += 12.5#进度条每次增加12.5
def homepage():#主页面
b01 = Button(game,bg='black',bd=0,font=(s_font,15),fg='orange',text=language[0],command=setpage)
b01.place(width=100,height=30,x=310,y=400)#设置按钮
b02 = Button(game,bg='black',bd=0,font=(s_font,15),fg='orange',text=language[1],command=playselect)
b02.place(width=100,height=30,x=430,y=400)#开始按钮
b03 = Button(game,bg='black',bd=0,font=(s_font,15),fg='orange',text=language[2],command=game.quit)
b03.place(width=100,height=30,x=550,y=400)#退出按钮
for i in [b01,b02,b03]:
i.bind('<Enter>',enter)
i.bind('<Leave>',leave)#按钮关联鼠标进入事件
def move(event):
global selfx,selfy
game.geometry(size+'+%s+%s'%(game.winfo_x()+event.x-selfx,game.winfo_y()+event.y-selfy))#窗口移动函数
def beforemove(event):
global selfx,selfy
selfx,selfy=event.x,event.y
game.bind('<B1-Motion>',lambda event:move(event))#鼠标左键一直按下移动事件关联
game.bind('<Button-1>',lambda event:beforemove(event))#鼠标左键按下移动事件关联
def setpage():#设置页面
f31 = Frame(game,bg='lightyellow')
f31.place(width=600,height=340,x=180,y=60)#设置页框架
Label(f31,font=(s_font,15),text=language[3],anchor='w',bg='grey').place(width=600,height=30)#设置页头部
Label(f31,bg='grey').place(width=600,height=40,y=300)#设置页底部
b31 = Button(f31,font=(s_font,15),text='×',bg='grey',bd=0,command=f31.destroy)
b31.place(width=30,height=30,x=570)#关闭按钮
b32 = Button(f31,font=(s_font,15),text='?',bg='grey',bd=0,command=lambda:sethelp())
b32.place(width=30,height=30,x=540)#帮助按钮
b33 = Button(f31,font=(s_font,15),bd=0,bg='lightgreen',text=language[10],command=lambda:okget())
b33.place(width=100,height=30,y=305,x=380)#确定按钮
b34 = Button(f31,font=(s_font,15),bd=0,bg='lightgreen',text=language[11],command=f31.destroy)
b34.place(width=100,height=30,y=305,x=490)#取消按钮
for i in range(5,10):Label(f31,font=(s_font,20),bg='lightyellow',text=language[i]).place(width=200,height=40,x=100,y=(i-4)*50)#各个设置项
e31 = Entry(f31,font=(s_font,20),bg='lightyellow',textvariable=s_1,bd=0,justify='center')
e31.place(width=150,height=40,x=350,y=50)#刷新率文本框
e32 = Entry(f31,font=(s_font,20),bg='lightyellow',textvariable=s_2,bd=0,justify='center')
e32.place(width=150,height=40,x=350,y=100)#透明度文本框
e33 = Entry(f31,font=(s_font,20),bg='lightyellow',textvariable=s_3,bd=0,justify='center')
e33.place(width=150,height=40,x=350,y=150)#字体文本框
b35 = Button(f31,font=(s_font,20),bg='lightyellow',textvariable=s_4,bd=0,command=lambda:cmd4())
b35.place(width=150,height=40,x=350,y=200)#语言切换
b36 = Button(f31,font=(s_font,20),bg='lightyellow',textvariable=s_5,bd=0,command=lambda:cmd5())
b36.place(width=150,height=40,x=350,y=250)#音乐开关
def cmd4():
global s_language
s_language = 'English' if s_language=='简体中文' else '简体中文'
s_4.set(s_language)#语言切换函数
def cmd5():
global s_audio
s_audio = 'On' if s_audio=='Off' else 'Off' if s_audio=='On' else '开' if s_audio=='关' else '关'
s_5.set(s_audio)#音乐开关函数
b31.bind('<Enter>',shutenter)
b31.bind('<Leave>',shutleave)#按钮关联鼠标进入事件
b32.bind('<Enter>',helpenter)
b32.bind('<Leave>',shutleave)#按钮关联鼠标进入事件
for i in [e31,e32,e33,b35,b36]:
i.bind('<Enter>',enter2)
i.bind('<Leave>',leave2)#按钮关联鼠标进入事件
for i in [b33,b34]:
i.bind('<Enter>',enter3)
i.bind('<Leave>',leave3)#按钮关联鼠标进入事件
def sethelp():#帮助页面
fhelp = Frame(f31)
fhelp.place(width=400,height=250,x=100,y=40)#帮助框架
Label(fhelp,bg='gray',font=(s_font,15),text=language[15]).place(width=400,height=30)#帮助页面头部
Label(fhelp,bg='gray',font=(s_font,15)).place(width=400,height=30,y=220)#帮助页面底部
Label(fhelp,text=language[17],font=(s_font,15)).place(width=400,height=190,y=30)#帮助主体内容
b37 = Button(fhelp,text=language[10],bd=0,bg='lightgreen',font=(s_font,12),command=fhelp.destroy)
b37.place(width=80,height=20,y=225,x=315)#确定按钮
b38 = Button(fhelp,text=language[16],bd=0,bg='lightgreen',font=(s_font,12),command=lambda:restoredefault())
b38.place(width=120,height=20,y=225,x=5)#默认设置按钮
for i in [b37,b38]:
i.bind('<Enter>',enter3)
i.bind('<Leave>',leave3)#按钮关联鼠标进入事件
def restoredefault():#默认设置函数
global s_gif,s_alpha,s_font,s_language,s_audio,language
s_1.set(s_gif:=10)
s_2.set(s_alpha:=1)
s_3.set(s_font:='华文新魏')
s_4.set(s_language:='English');language = Englishfont
s_5.set(s_audio:=language[13])
fhelp.destroy()#关闭帮助页面
def okget():#设置改变函数
global s_gif,s_alpha,s_font,s_language,s_audio,language
f31.destroy()
if 0<float(s_1.get())<=1000:
s_gif = s_1.get()#设置刷新率
else:
s_1.set(s_gif:=10)#切换为默认值
if 0<float(s_2.get())<=1:
s_alpha = s_2.get()#设置透明度
else:
s_2.set(s_alpha:=1)#切换为默认值
s_font = s_3.get()#字体切换
language = Englishfont if s_language == 'English' else Chinesefont#语言切换
if s_audio == 'On' or s_audio == '开':
s_5.set(s_audio:=language[13])
pygame.mixer.music.unpause()#音乐继续播放
if not pygame.mixer.music.get_busy():pygame.mixer.music.play(loops=10)
else:
s_5.set(s_audio:=language[14])
pygame.mixer.music.pause()#音乐暂停
game.wm_attributes("-alpha",s_alpha)
homepage()#改变系统变量并重新加载
def playselect():#开始页面
f11 = Frame(game,bg='lightyellow')
f11.place(width=200,height=340,x=380,y=60)#开始页面框架
Label(f11,font=(s_font,15),text=language[4],anchor='w',bg='grey').place(width=200,height=30)#开始页面头部
b11 = Button(f11,font=(s_font,15),text='×',bg='grey',bd=0,command=f11.destroy)
b11.place(width=30,height=30,x=170)#关闭按钮
for i in range(len(lis:=[Button(f11)]*7)):
lis[i]=Button(f11,bg='lightyellow',font=(s_font,15),bd=0,text=gamelist[i],command=lambda arg=i:gamestart(arg+1))
lis[i].place(width=180,height=30,x=10,y=i*40+50)
b11.bind('<Enter>',shutenter)
b11.bind('<Leave>',shutleave)#按钮关联鼠标进入事件
for i in lis:
i.bind('<Enter>',enter2)
i.bind('<Leave>',leave2)#按钮关联鼠标进入事件
def gamestart(n):
pygame.mixer.music.stop()
f11.destroy()
if n == 1:Game1()
elif n == 2:Game2()
elif n == 3:Game3()
elif n == 4:Game4()
elif n == 5:Game5()
elif n == 6:Game6()
else:None
load()#启动加载函数
game.mainloop()#进入消息事件循环
这个只有区区的500多行代码,还不算很多,但是它是一个游戏盒子,所以里面是可以装游戏的(所以代码可能会更多),按照前面所说的,它还可以加5个游戏(理论上加个滚动条可以弄无限个游戏),期待有人可以把里面的游戏都做出来哦(我在做了)
更多关于Tkinter模块的教程请参见【Python Tkinter 界面化编程】
这么多内容还真不简单呢,你们不点个赞,收个藏咩???
完整程序及源码下载链接【蓝奏云】:GameBox.zip【密码:664w】
【下期预告:Python Tkinter编写人机对战五子棋】【下期链接:人机对战五子棋】