python实现简单俄罗斯方块
本文实例为大家分享了python实现俄罗斯方块的具体代码,供大家参考,具体内容如下
#teris.py
#Amoduleforgameteris.
#ByprogrammerFYJ
fromtkinterimport*
fromtimeimportsleep
fromrandomimport*
fromtkinterimportmessagebox
classTeris:
def__init__(self):
#方块颜色列表
self.color=['red','orange','yellow','purple','blue','green','pink']
#Setacoresqureandanyshapecanbedrawnbytherelativelocation.
#字典存储形状对应7种形状元组存储坐标
self.shapeDict={1:[(0,0),(0,-1),(0,-2),(0,1)],#shapeI
2:[(0,0),(0,-1),(1,-1),(1,0)],#shapeO
3:[(0,0),(-1,0),(0,-1),(1,0)],#shapeTT型
4:[(0,0),(0,-1),(1,0),(2,0)],#shapeJ右长倒L盖子
5:[(0,0),(0,-1),(-1,0),(-2,0)],#shapeL
6:[(0,0),(0,-1),(-1,-1),(1,0)],#shapeZ
7:[(0,0),(-1,0),(0,-1),(1,-1)]}#shapeS
#旋转坐标控制
self.rotateDict={(0,0):(0,0),(0,1):(-1,0),(0,2):(-2,0),(0,-1):(1,0),
(0,-2):(2,0),(1,0):(0,1),(2,0):(0,2),(-1,0):(0,-1),
(-2,0):(0,-2),(1,1):(-1,1),(-1,1):(-1,-1),
(-1,-1):(1,-1),(1,-1):(1,1)}
#初始高度,宽度核心块位置
self.coreLocation=[4,-2]
self.height,self.width=20,10
self.size=32
#Mapcanrecordthelocationofeverysquare.i宽j高
self.map={}
#全部置0
foriinrange(self.width):
forjinrange(-4,self.height):
self.map[(i,j)]=0
#添加边界
foriinrange(-4,self.width+4):
self.map[(i,self.height)]=1
forjinrange(-4,self.height+4):
foriinrange(-4,0):
self.map[(i,j)]=1
forjinrange(-4,self.height+4):
foriinrange(self.width,self.width+4):
self.map[(i,j)]=1
#初始化分数0默认不加快按下时加快
self.score=0
self.isFaster=False
#创建GUI界面
self.root=Tk()
self.root.title("Teris")
self.root.geometry("500x645")
self.area=Canvas(self.root,width=320,height=640,bg='white')
self.area.grid(row=2)
self.pauseBut=Button(self.root,text="Pause",height=2,width=13,font=(18),command=self.isPause)
self.pauseBut.place(x=340,y=100)
self.startBut=Button(self.root,text="Start",height=2,width=13,font=(18),command=self.play)
self.startBut.place(x=340,y=20)
self.restartBut=Button(self.root,text="Restart",height=2,width=13,font=(18),command=self.isRestart)
self.restartBut.place(x=340,y=180)
self.quitBut=Button(self.root,text="Quit",height=2,width=13,font=(18),command=self.isQuit)
self.quitBut.place(x=340,y=260)
self.scoreLabel1=Label(self.root,text="Score:",font=(24))
self.scoreLabel1.place(x=340,y=600)
self.scoreLabel2=Label(self.root,text="0",fg='red',font=(24))
self.scoreLabel2.place(x=410,y=600)
#按键交互
self.area.bind("",self.rotate)
self.area.bind("",self.moveLeft)
self.area.bind("",self.moveRight)
self.area.bind("",self.moveFaster)
self.area.bind("",self.rotate)
self.area.bind("",self.moveLeft)
self.area.bind("",self.moveRight)
self.area.bind("",self.moveFaster)
self.area.focus_set()
#菜单
self.menu=Menu(self.root)
self.root.config(menu=self.menu)
self.startMenu=Menu(self.menu)
self.menu.add_cascade(label='Start',menu=self.startMenu)
self.startMenu.add_command(label='NewGame',command=self.isRestart)
self.startMenu.add_separator()
self.startMenu.add_command(label='Continue',command=self.play)
self.exitMenu=Menu(self.menu)
self.menu.add_cascade(label='Exit',command=self.isQuit)
self.helpMenu=Menu(self.root)
self.menu.add_cascade(label='Help',menu=self.helpMenu)
self.helpMenu.add_command(label='Howtoplay',command=self.rule)
self.helpMenu.add_separator()
self.helpMenu.add_command(label='About...',command=self.about)
#先将核心块的所在位置在map中的元素设为1,通过self.shapeDict获取其余方块位置,将map中对应元素设为1。
defgetLocation(self):
map[(core[0],core[1])]=1
foriinrange(4):
map[((core[0]+getNew[i][0]),
(core[1]+getNew[i][1]))]=1
#判断方块下移一格后对应位置map中的元素是否为一,是,则不可移动,返回False;否,可以移动,返回True。
defcanMove(self):
foriinrange(4):
ifmap[(core[0]+getNew[i][0]),(core[1]+1+getNew[i][1])]==1:
returnFalse
returnTrue
#先用randRange获取1~7中的随机整数,随机到某一整数,那么访问self.shapeDict,获取这种形状方块的核心块及其他方块的相对位置。
#访问颜色字典,获取此方块的颜色。建立循环,当方块可移动时(whileself.canMove():),且暂停键未被摁下(ifisPause:),
#核心块纵坐标加一,根据核心块及其他方块对于核心块的相对位置,画出四个方块。用self.getLocation()函数获取方块的位置。
defdrawNew(self):
globalnext
globalgetNew
globalcore
next=randrange(1,8)
#形状
self.getNew=self.shapeDict[next]
getNew=self.getNew
core=[4,-2]
time=0.2
whileself.canMove():
ifisPause:
core[1]+=1
self.drawSquare()
ifself.isFaster:
sleep(time-0.15)
else:
sleep(time+0.22)
self.isFaster=False
else:
self.drawSquare()
sleep(time)
self.getLocation()
#绘制当前方块
defdrawSquare(self):
self.area.delete("new")
foriinrange(4):
self.area.create_rectangle((core[0]+self.getNew[i][0])*self.size,
(core[1]+self.getNew[i][1])*self.size,
(core[0]+self.getNew[i][0]+1)*self.size,
(core[1]+self.getNew[i][1]+1)*self.size,
fill=self.color[next-1],tags="new")
self.area.update()
#给底部每行中方块都加上标签:bottom+str(j),j代表该块所在行数,每次遍历map,建立对于range(self.height)的for循环,删去每一行,
#若map什么地方的元素为1,画出这一位置的方块,不断更新。这样可以画出底部方块。
defdrawBottom(self):
forjinrange(self.height):
self.area.delete('bottom'+str(j))
foriinrange(self.width):
ifmap[(i,j)]==1:
self.area.create_rectangle(self.size*i,self.size*j,self.size*(i+1),
self.size*(j+1),fill='grey',tags='bottom'+str(j))
self.area.update()
#判断填满遍历map每一行的各个元素,若所有元素为1,则标签中score值+10,将
#此行所有元素改为0,行数map(i,j)=map(i-1,j)(即所有之上的行下移)
#,那么后续画底部方块时,可实现消行。
defisFill(self):
forjinrange(self.height):
t=0
foriinrange(self.width):
ifmap[(i,j)]==1:
t=t+1
ift==self.width:
self.getScore()
self.deleteLine(j)
#加分
defgetScore(self):
scoreValue=eval(self.scoreLabel2['text'])
scoreValue+=10
self.scoreLabel2.config(text=str(scoreValue))
#消行
defdeleteLine(self,j):
fortinrange(j,2,-1):
foriinrange(self.width):
map[(i,t)]=map[(i,t-1)]
foriinrange(self.width):
map[(i,0)]=0
self.drawBottom()
#遍历每一行,若从顶部到底部map每一行都有某一个元素或更多元素为1,
#那么说明方块以顶到最上端,游戏结束。此处不可以简单判定最上一行是否有元素为1就判定结束,
#若这样会产生顶部有新的方块产生,然后导致顶部有元素为1,误判为游戏结束。
defisOver(self):
t=0
forjinrange(self.height):
foriinrange(self.width):
ifself.map[(i,j)]==1:
t+=1
break
ift>=self.height:
returnFalse
else:
returnTrue
#先判断方块是否可以旋转(针对其靠近边界时)。先将其现在所在位置对应map中的元素改为0,判断其旋
#转后位置对应map中的元素是否有一,若有,说明其旋转后的位置已经被占,是不能旋转的,返回值为False
#。否则为可旋转,返回值True。若已判定可以旋转,那么访问self.rotateDict,得出旋转以后所有小块的位置
#变换,将变换以后的位置对应map的元素设为1,旋转便已完成。
defcanRotate(self):
foriinrange(4):
map[((core[0]+getNew[i][0]),
(core[1]+getNew[i][1]))]=0
foriinrange(4):
ifmap[((core[0]+self.rotateDict[getNew[i]][0]),
(core[1]+self.rotateDict[getNew[i]][1]))]==1:
returnFalse
returnTrue
#旋转
defrotate(self,event):
ifnext!=2:
ifself.canRotate():
foriinrange(4):
getNew[i]=self.rotateDict[getNew[i]]
self.drawSquare()
ifnotself.canMove():
foriinrange(4):
map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))]=1
#先判断是否左移/右移,同样,将方块现在所处位置的map中元素设为0,看其移动后的位置上map的元素是否有1,
#若有,说明这一位置已被占据或已到边界,不可移动,返回False。若可移动,返回True。按下左键,若可
#以移动,核心块的横坐标减1,由于我们只讨论其他小块对于核心块的相对位置,所以其他小块的位置自动随
#核心块的位置移动而移动。将移动过后的位置对应map中的元素设为1。
defcanLeft(self):
coreNow=core
foriinrange(4):
map[((coreNow[0]+getNew[i][0]),(coreNow[1]+getNew[i][1]))]=0
foriinrange(4):
ifmap[((coreNow[0]+getNew[i][0]-1),(coreNow[1]+getNew[i][1]))]==1:
returnFalse
returnTrue
#左移
defmoveLeft(self,event):
ifself.canLeft():
core[0]-=1
self.drawSquare()
self.drawBottom()
ifnotself.canMove():
foriinrange(4):
map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))]=1
#判断右移
defcanRight(self):
foriinrange(4):
map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))]=0
foriinrange(4):
ifmap[((core[0]+getNew[i][0]+1),(core[1]+getNew[i][1]))]==1:
returnFalse
returnTrue
#右移
defmoveRight(self,event):
ifself.canRight():
core[0]+=1
self.drawSquare()
self.drawBottom()
ifnotself.canMove():
foriinrange(4):
map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))]=1
#初始化中有一self.isFaster的变量被设为False,当其为False时,
#程序中的sleep(time)中time的值为0.35,而按下下键,self.isFaster变为True,
#time变成0.05,通过调整sleep()中变量的大小可以调节方块运动的速度。
#此功能通过if语句实现。
defmoveFaster(self,event):
self.isFaster=True
ifnotself.canMove():
foriinrange(4):
map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))]=1
#runtheprograme
defrun(self):
self.isFill()
self.drawNew()
self.drawBottom()
#playthegame
defplay(self):
self.startBut.config(state=DISABLED)
globalisPause
isPause=True
globalmap
map=self.map
whileTrue:
ifself.isOver():
self.run()
else:
break
self.over()
#重新开始游戏
defrestart(self):
self.core=[4,-2]
self.map={}
foriinrange(self.width):
forjinrange(-4,self.height):
self.map[(i,j)]=0
foriinrange(-1,self.width):
self.map[(i,self.height)]=1
forjinrange(-4,self.height+1):
self.map[(-1,j)]=1
self.map[(self.width,j)]=1
self.score=0
self.t=0.07
forjinrange(self.height):
self.area.delete('bottom'+str(j))
self.play()
#结束后告诉用户失败
defover(self):
feedback=messagebox.askquestion("YouLose!","YouLose!\nDoyouwanttorestart?")
iffeedback=='yes':
self.restart()
else:
self.root.destroy()
#退出
defisQuit(self):
askQuit=messagebox.askquestion("Quit","Areyousuretoquit?")
ifaskQuit=='yes':
self.root.destroy()
exit()
#判断是否按下restart
defisRestart(self):
askRestart=messagebox.askquestion("Restart","Areyousuretorestart?")
ifaskRestart=='yes':
self.restart()
else:
return
#每次一按下暂停键,isPause=notisPause,当isPause=True时,由于之前提到过的ifisPause:语句,
#方块可以移动,游戏运行。当按下暂停键以后,isPause值为False,方块将不可移动。同时,isPause值为False时
#,暂停键变为开始键,即标签由Pause改为Resume,当isPause值为True时,Resume改为Pause。这一功能由if语句实现。
defisPause(self):
globalisPause
isPause=notisPause
ifnotisPause:
self.pauseBut["text"]="Resume"
else:
self.pauseBut["text"]="Pause"
#帮助
defrule(self):
ruleTop=Toplevel()
ruleTop.title('Help')
ruleTop.geometry('800x400')
rule="Start:Pressthestartbuttonorchoosetheoption'Continue'tostartthegame.\n%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s"%("Restart:Presstherestartbuttonorchoosetheoption'NewGame'toresatrtthegame.\n","EnjoytheTerisgame!Havefun!")
ruleLabel=Label(ruleTop,text=rule,fg='blue',font=(18))
ruleLabel.place(x=50,y=50)
#显示有关信息
defabout(self):
aboutTop=Toplevel()
aboutTop.title('About')
aboutTop.geometry('300x150')
about="Teris.py\n\
ByProgrammerLee\n\
AllRightsReserved."
aboutLabel=Label(aboutTop,font=('Curier',20),fg='darkblue',text=about)
aboutLabel.pack()
#Getintomainloop
defmainloop(self):
self.root.mainloop()
#TerisPlay.py
#GameTeris
#ByprogrammerFYJ
fromterisimport*
defmain():
teris=Teris()
teris.mainloop()
main()
运行结构如图所示:
更多俄罗斯方块精彩文章请点击专题:俄罗斯方块游戏集合进行学习。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。