python实现简单俄罗斯方块


Posted in Python onMarch 13, 2020

本文实例为大家分享了python实现俄罗斯方块的具体代码,供大家参考,具体内容如下

# teris.py
# A module for game teris.
# By programmer FYJ

from tkinter import *
from time import sleep
from random import *
from tkinter import messagebox


class Teris:
  def __init__(self):
    #方块颜色列表
    self.color = ['red','orange','yellow','purple','blue','green','pink']
    # Set a core squre and any shape can be drawn by the relative location.
    #字典 存储形状对应7种形状 元组存储坐标
    self.shapeDict = {1:[(0,0),(0,-1),(0,-2),(0,1)], # shape I
              2:[(0,0),(0,-1),(1,-1),(1,0)], # shape O 
              3:[(0,0),(-1,0),(0,-1),(1,0)], # shape T T型
              4:[(0,0),(0,-1),(1,0),(2,0)], # shape J 右长倒L盖子
              5:[(0,0),(0,-1),(-1,0),(-2,0)], # shape L
              6:[(0,0),(0,-1),(-1,-1),(1,0)], # shape Z
              7:[(0,0),(-1,0),(0,-1),(1,-1)]} # shape S
    #旋转坐标控制
    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
    # Map can record the location of every square.i宽 j高
    self.map = {}
    #全部置0
    for i in range(self.width):
      for j in range(-4,self.height):
        self.map[(i,j)] = 0
    #添加边界
    for i in range(-4,self.width+4):
      self.map[(i,self.height)] = 1
    for j in range(-4,self.height+4):
      for i in range(-4,0):
        self.map[(i,j)] = 1
    for j in range(-4,self.height+4):
      for i in range(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("<Up>",self.rotate)
    self.area.bind("<Left>",self.moveLeft)
    self.area.bind("<Right>",self.moveRight)
    self.area.bind("<Down>",self.moveFaster)
    self.area.bind("<Key-w>",self.rotate)
    self.area.bind("<Key-a>",self.moveLeft)
    self.area.bind("<Key-d>",self.moveRight)
    self.area.bind("<Key-s>",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='New Game',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='How to play',command=self.rule)
    self.helpMenu.add_separator()
    self.helpMenu.add_command(label='About...',command=self.about)

  #先将核心块的所在位置在map中的元素设为1,通过self.shapeDict获取其余方块位置,将map中对应元素设为1。
  def getLocation(self):
    map[(core[0],core[1])] = 1
    for i in range(4):
      map[((core[0]+getNew[i][0]),
         (core[1]+getNew[i][1]))]=1

  #判断方块下移一格后对应位置map中的元素是否为一,是,则不可移动,返回False;否,可以移动,返回True。
  def canMove(self):
    for i in range(4):
      if map[(core[0]+getNew[i][0]),(core[1]+1+getNew[i][1])] == 1:
        return False
    return True

  # 先用randRange获取1~7中的随机整数,随机到某一整数,那么访问self.shapeDict,获取这种形状方块的核心块及其他方块的相对位置。
  # 访问颜色字典,获取此方块的颜色。建立循环,当方块可移动时(while self. canMove():),且暂停键未被摁下(if isPause:),
  # 核心块纵坐标加一,根据核心块及其他方块对于核心块的相对位置,画出四个方块。用self.getLocation()函数获取方块的位置。
  def drawNew(self):
    global next
    global getNew
    global core
    next = randrange(1,8)
    #形状
    self.getNew = self.shapeDict[next]
    getNew = self.getNew
    core = [4,-2]
    time = 0.2
    while self.canMove():
      if isPause:
        core[1] += 1
        self.drawSquare()
        if self.isFaster:
          sleep(time-0.15)
        else:
          sleep(time+0.22)
        self.isFaster = False  
      else:
        self.drawSquare()
        sleep(time)
    self.getLocation()

  # 绘制当前方块
  def drawSquare(self):
    self.area.delete("new")
    for i in range(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,画出这一位置的方块,不断更新。这样可以画出底部方块。
  def drawBottom(self):
    for j in range(self.height):
      self.area.delete('bottom'+str(j))
      for i in range(self.width):
        if map[(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)(即所有之上的行下移)
  # ,那么后续画底部方块时,可实现消行。
  def isFill(self):
    for j in range(self.height):
      t = 0
      for i in range(self.width):
        if map[(i,j)] == 1:
          t = t + 1
      if t == self.width:
        self.getScore()
        self.deleteLine(j)

  # 加分
  def getScore(self):
    scoreValue = eval(self.scoreLabel2['text'])
    scoreValue += 10
    self.scoreLabel2.config(text=str(scoreValue))

  # 消行
  def deleteLine(self,j):
    for t in range(j,2,-1):
      for i in range(self.width):
        map[(i,t)] = map[(i,t-1)]
    for i in range(self.width):
      map[(i,0)] = 0
    self.drawBottom()
        

  # 遍历每一行,若从顶部到底部map每一行都有某一个元素或更多元素为1,
  # 那么说明方块以顶到最上端,游戏结束。此处不可以简单判定最上一行是否有元素为1就判定结束,
  # 若这样会产生顶部有新的方块产生,然后导致顶部有元素为1,误判为游戏结束。
  def isOver(self):
    t = 0
    for j in range(self.height):
      for i in range(self.width):
        if self.map[(i,j)] == 1:
          t += 1
          break
    if t >= self.height:
      return False
    else:
      return True

  # 先判断方块是否可以旋转(针对其靠近边界时)。先将其现在所在位置对应map中的元素改为0,判断其旋
  # 转后位置对应map中的元素是否有一,若有,说明其旋转后的位置已经被占,是不能旋转的,返回值为False
  # 。否则为可旋转,返回值True。若已判定可以旋转,那么访问self.rotateDict,得出旋转以后所有小块的位置
  # 变换,将变换以后的位置对应map的元素设为1,旋转便已完成。
  def canRotate(self):
    for i in range(4):
      map[((core[0]+getNew[i][0]),
        (core[1]+getNew[i][1]))] = 0
    for i in range(4):
      if map[((core[0]+self.rotateDict[getNew[i]][0]),
          (core[1]+self.rotateDict[getNew[i]][1]))] == 1:
        return False
    return True

  #旋转
  def rotate(self,event):
    if next != 2:
      if self.canRotate():
        for i in range(4):
          getNew[i] = self.rotateDict[getNew[i]]
        self.drawSquare()    
    if not self.canMove():
      for i in range(4):
        map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))] = 1

  # 先判断是否左移/右移,同样,将方块现在所处位置的map中元素设为0,看其移动后的位置上map的元素是否有1,
  # 若有,说明这一位置已被占据或已到边界,不可移动,返回False。若可移动,返回True。按下左键,若可
  # 以移动,核心块的横坐标减1,由于我们只讨论其他小块对于核心块的相对位置,所以其他小块的位置自动随
  # 核心块的位置移动而移动。将移动过后的位置对应map中的元素设为1。
  def canLeft(self):
    coreNow = core
    for i in range(4):
      map[((coreNow[0]+getNew[i][0]),(coreNow[1]+getNew[i][1]))] = 0
    for i in range(4):
      if map[((coreNow[0]+getNew[i][0]-1),(coreNow[1]+getNew[i][1]))] == 1:
        return False
    return True

  #左移
  def moveLeft(self,event):
    if self.canLeft():
      core[0] -= 1
      self.drawSquare()
      self.drawBottom()
    if not self.canMove():
      for i in range(4):
        map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))] = 1

       
  # 判断右移
  def canRight(self):
    for i in range(4):
      map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))] = 0
    for i in range(4):
      if map[((core[0]+getNew[i][0]+1),(core[1]+getNew[i][1]))] == 1:
        return False
    return True

  # 右移
  def moveRight(self,event):
    if self.canRight():
      core[0] += 1
      self.drawSquare()
      self.drawBottom()
    if not self.canMove():
      for i in range(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语句实现。
  def moveFaster(self,event):
    self.isFaster = True
    if not self.canMove():
      for i in range(4):
        map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))] = 1
    
  # run the programe
  def run(self):
    self.isFill()
    self.drawNew()
    self.drawBottom()

  # play the game  
  def play(self):
    self.startBut.config(state=DISABLED)
    global isPause
    isPause = True
    global map
    map = self.map
    while True:
      if self.isOver():
        self.run()
      else:
        break
    self.over()  

  # 重新开始游戏   
  def restart(self):
    self.core = [4,-2]
    self.map = {}
    for i in range(self.width):
      for j in range(-4,self.height):
        self.map[(i,j)] = 0
    for i in range(-1,self.width):
      self.map[(i,self.height)] = 1
    for j in range(-4,self.height+1):
      self.map[(-1,j)] = 1
      self.map[(self.width,j)] = 1    
    self.score = 0
    self.t = 0.07
    for j in range(self.height):
      self.area.delete('bottom'+str(j))
    self.play()

  # 结束后告诉用户失败
  def over(self):
    feedback =messagebox.askquestion("You Lose!","You Lose!\nDo you want to restart?")
    if feedback == 'yes':
      self.restart()
    else:
      self.root.destroy()

  # 退出
  def isQuit(self):
    askQuit =messagebox.askquestion("Quit","Are you sure to quit?")
    if askQuit == 'yes':
      self.root.destroy()
      exit()

  #判断是否按下restart
  def isRestart(self):
    askRestart =messagebox.askquestion("Restart","Are you sure to restart?")
    if askRestart == 'yes':
      self.restart()
    else:
      return

  # 每次一按下暂停键,isPause = not isPause,当isPause = True时,由于之前提到过的if isPause:语句,
  # 方块可以移动,游戏运行。当按下暂停键以后,isPause值为False,方块将不可移动。同时,isPause值为False时
  # ,暂停键变为开始键,即标签由Pause 改为 Resume,当isPause值为True时,Resume改为Pause。这一功能由if语句实现。
  def isPause(self):
    global isPause
    isPause=not isPause
    if not isPause:
      self.pauseBut["text"]="Resume"
    else:
      self.pauseBut["text"]="Pause"
    
  #帮助
  def rule(self):
    ruleTop = Toplevel()
    ruleTop.title('Help')
    ruleTop.geometry('800x400')
    rule ="Start: Press the start button or choose the option 'Continue' to start the game.\n%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s"%("Restart: Press the restart button or choose the option 'New Game' to resatrt the game.\n",                                                                   "Enjoy the Teris game! Have fun!")
    ruleLabel = Label(ruleTop,text=rule,fg='blue',font=(18))
    ruleLabel.place(x=50,y=50)

  # 显示有关信息
  def about(self):
    aboutTop = Toplevel()
    aboutTop.title('About')
    aboutTop.geometry('300x150')
    about = "Teris.py\n\
By Programmer Lee\n\
All Rights Reserved."
    aboutLabel = Label(aboutTop,font=('Curier',20),fg='darkblue',text=about)
    aboutLabel.pack()        

  # Get into mainloop
  def mainloop(self):
    self.root.mainloop()


# TerisPlay.py
# Game Teris
# By programmer FYJ

from teris import *

def main():
  teris = Teris()
  teris.mainloop()
  
main()

运行结构如图所示:

python实现简单俄罗斯方块

更多俄罗斯方块精彩文章请点击专题:俄罗斯方块游戏集合 进行学习。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python和C语言混合编程实例
Jun 04 Python
Python中的rjust()方法使用详解
May 19 Python
Python编程之多态用法实例详解
May 19 Python
Tornado 多进程实现分析详解
Jan 12 Python
浅谈Django中的数据库模型类-models.py(一对一的关系)
May 30 Python
mac下给python3安装requests库和scrapy库的实例
Jun 13 Python
在Python中构建增广矩阵的实现方法
Jul 01 Python
Python DataFrame一列拆成多列以及一行拆成多行
Aug 06 Python
Python3 JSON编码解码方法详解
Sep 06 Python
python绘制趋势图的示例
Sep 17 Python
python遍历路径破解表单的示例
Nov 21 Python
Python可视化学习之matplotlib内置单颜色
Feb 24 Python
Python实现检测文件的MD5值来查找重复文件案例
Mar 12 #Python
python 判断txt每行内容中是否包含子串并重新写入保存的实例
Mar 12 #Python
python 两个一样的字符串用==结果为false问题的解决
Mar 12 #Python
python不相等的两个字符串的 if 条件判断为True详解
Mar 12 #Python
Python 实现使用空值进行赋值 None
Mar 12 #Python
PyCharm永久激活方式(推荐)
Sep 22 #Python
Pycharm激活码激活两种快速方式(附最新激活码和插件)
Mar 12 #Python
You might like
PHP保留两位小数并且四舍五入及不四舍五入的方法
2013/09/22 PHP
FleaPHP框架数据库查询条件($conditions)写法总结
2016/03/19 PHP
使用phpexcel类实现excel导入mysql数据库功能(实例代码)
2016/05/12 PHP
php使用ftp实现文件上传与下载功能
2017/07/21 PHP
PHP7下协程的实现方法详解
2017/12/17 PHP
IE php关于强制下载文件的代码
2008/08/23 Javascript
jquery仿搜索自动联想功能代码
2014/05/23 Javascript
Javascript学习笔记之 函数篇(二) : this 的工作机制
2014/06/24 Javascript
jQuery ajax时间差导致的变量赋值问题分析
2016/01/22 Javascript
jQuery实现可展开折叠的导航效果示例
2016/09/12 Javascript
利用js来实现缩略语列表、文献来源链接和快捷键列表
2016/12/16 Javascript
关于微信小程序bug记录与解决方法
2018/08/15 Javascript
轻松学习JavaScript函数中的 Rest 参数
2019/05/30 Javascript
Vue Cli3 打包配置并自动忽略console.log语句的方法
2020/04/23 Javascript
vue中touch和click共存的解决方式
2020/07/28 Javascript
如何利用node转发请求详解
2020/09/17 Javascript
Python3使用requests包抓取并保存网页源码的方法
2016/03/15 Python
浅谈终端直接执行py文件,不需要python命令
2017/01/23 Python
分享一下如何编写高效且优雅的 Python 代码
2017/09/07 Python
CentOS下Python3的安装及创建虚拟环境的方法
2018/11/28 Python
tensorboard 可以显示graph,却不能显示scalar的解决方式
2020/02/15 Python
使用opencv识别图像红色区域,并输出红色区域中心点坐标
2020/06/02 Python
Python实现Kerberos用户的增删改查操作
2020/12/14 Python
CSS3 重置iphone浏览器按钮input,select等表单元素的默认样式
2014/10/11 HTML / CSS
canvas实现飞机打怪兽射击小游戏的示例代码
2018/07/09 HTML / CSS
使用Html5 Stream开发实时监控系统
2020/06/02 HTML / CSS
eBay德国站:eBay.de
2017/09/14 全球购物
纽约手袋品牌:KARA
2018/03/18 全球购物
2014年自我评价
2014/01/04 职场文书
员工工作表扬信范文
2014/01/13 职场文书
进口业务员岗位职责
2014/04/06 职场文书
出纳岗位职责范本
2015/03/31 职场文书
初三毕业感言
2015/07/31 职场文书
诚信教育主题班会
2015/08/13 职场文书
vue实现简单数据双向绑定
2021/04/28 Vue.js
Python 中的Sympy详细使用
2021/08/07 Python