用Tkinter模块编写一个大鱼吃小鱼游戏
【先来看看效果图】
【玩家有3条生命,在右上角的红色方块显示】
【初始时,有一个帮助对话框(画出来的)】
【玩家是中间那个小黑鱼,白色的圆形是鱼眼(比较简陋,勿喷)】
——玩家:这鱼怎么这么丑,方方正正的,《我的世界》里的鱼都比这“玩意儿”好看!
——小鱼:你礼貌吗?
【新鱼刷新时间随机,颜色随机,大小随机,速度随机,位置随机,朝向随机,鱼眼大小随机】
【玩家扣血后会有1秒无敌时间】
【死亡界面,胜利界面就不展示了(我玩了半天也没胜利 ToT)】
【有胜利的伙伴们可以在评论区留言哟!】
【不妨看看编写思路】
程序实现功能清单
游戏任务:大鱼吃小鱼游戏
游戏规则:玩家3条命;扣血之后一秒无敌
分数增加:吃掉鱼的长宽之和
碰撞检测:产生碰撞时,比较玩家和碰撞鱼的面积大小,以此进行死亡和加分判断
【再来看看源代码】
【源码中几乎每行后都有详细注释,方便大家理解】
from tkinter import *#引入界面化编程模块 from random import *#引入随机数模块 game = Tk()#创建窗口 game.geometry('960x480+150+100')#设置窗口大小及位置 game.resizable(0,0)#设置窗口大小为不可更改 class Game0:#定义Game类,方便重置游戏 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']#RGB码所有颜色字符 self.Score=IntVar()#分数显示变量 self.Score.set(self.score)#设置界面化中的分数为初始分数 self.Game = Frame(game)#定义框架,方便删除 self.Game.place(width=960,height=480) self.main = Frame(self.Game)#定义框架,方便删除 self.main.place(width=960,height=480) self.player = Label(self.Game,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.Game,bg='lightgreen',textvariable=self.Score,font=('华文新魏',20)).place(width=960,height=40)#背景 for i in range(3):Label(self.Game,bg='red').place(width=30,height=30,y=5,x=925-35*i)#命数显示 self.life = Label(self.Game,bg='lightgreen') self.life.place(height=40,x=845,width=0) Button(self.Game,bd=0,bg='orange',text='退出',font=('华文新魏',15),command=lambda:self.fishquit()).place(width=100,height=30,y=5,x=5)#退出按钮 Button(self.Game,bd=0,bg='orange',text='重置',font=('华文新魏',15),command=lambda:self.fishagain()).place(width=100,height=30,y=5,x=110)#重置按钮 self.Gamestart()#执行Gamestart函数 game.mainloop()#窗口进入消息事件循环 def Gamestart(self): Gamehelp = Frame(self.Game)#帮助对话框 Gamehelp.place(width=600,height=360,y=60,x=180) Label(Gamehelp,text='帮助',bg='grey',font=('华文新魏',15)).place(width=600,height=30)#帮助对话框标题 Label(Gamehelp,bg='lightgreen',font=('华文新魏',20),text='按‘w’、‘s’、‘a’和‘d’进行移动!\n4000分胜利!\n祝你好运!').place(width=600,height=300,y=30)#帮助对话框主体 Label(Gamehelp,bg='grey').place(width=600,height=30,y=330) Button(Gamehelp,bg='lightgreen',text='确定',bd=0,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()#开始随机产生鱼 Gamehelp.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.Game.destroy()#摧毁之前的界面,释放内存 Game0()#重置游戏,重新实例化类 def fishquit(self):game.quit()#退出游戏 def victory(self):#胜利设定 if self.score >= 4000:#4000分胜利 Label(self.Game,bg='lightyellow',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:#死亡次数小于3 self.god = True if self.god == False else False#切换无敌模式的开关 self.life.place(height=40,x=845,width=self.count*40) else:#3条命都已用完 self.life.place(height=40,x=845,width=120) self.main.destroy()#摧毁之前的界面,释放内存 Label(self.Game,bg='lightyellow',font=('华文新魏',100),text='- You Dead -',fg='orange').place(width=960,height=440,y=40) if self.god == True:#打开无敌模式 self.count-=1#死亡减一(与前面的死亡次数加一抵消) self.Game.after(1000,self.death)#1000ms后关闭无敌模式 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#鱼每10ms的横坐标方向位移 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)#每1000ms到3000ms内随机产生一条新鱼 def playmove(self,way):#玩家移动 #计算玩家位置 if way == 'w' and self.py>40:#按下w键 self.py-=10 elif way == 's' and self.py<=470-self.ph:#按下s键 self.py+=10 elif way == 'a' and self.px>0:#按下a键 self.px-=10 self.player.config(anchor='w')#设置鱼头朝向 elif way == 'd' and self.px<=955-self.pw:#按下d键 self.px+=10 self.player.config(anchor='e')#设置鱼头朝向 self.player.place(width=self.pw,height=self.ph,y=self.py,x=self.px)#移动玩家位置 Game0()#实例化该类
其实是可以用一个类来实现鱼的随机产生的,但是我这里用的是函数,通过函数的传参来实现于类相似的功能,这里要注意的难点应该就是函数的传参了
说明:关于这个鱼的样式,我没有特别地去进行美化,大家可以用Label控件的image参数来给鱼贴上贴图美化它们,我这里只是写个框架,细节可以由大家自由发挥