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中用函数作为返回值和实现闭包的教程
Apr 27 Python
Python中的字符串替换操作示例
Jun 27 Python
Python中几种导入模块的方式总结
Apr 27 Python
Python中matplotlib中文乱码解决办法
May 12 Python
使用python实现链表操作
Jan 26 Python
python实现自动登录后台管理系统
Oct 18 Python
python try except 捕获所有异常的实例
Oct 18 Python
对Python3.x版本print函数左右对齐详解
Dec 22 Python
python根据文章标题内容自动生成摘要的实例
Feb 21 Python
Django shell调试models输出的SQL语句方法
Aug 29 Python
Tensorflow tf.tile()的用法实例分析
May 22 Python
python中subplot大小的设置步骤
Jun 28 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
html中select语句读取mysql表中内容
2006/10/09 PHP
PHP 远程文件管理,可以给表格排序,遍历目录,时间排序
2009/08/07 PHP
php垃圾代码优化操作代码
2010/08/05 PHP
PHP的Yii框架中使用数据库的配置和SQL操作实例教程
2016/03/17 PHP
laravel通过创建自定义artisan make命令来新建类文件详解
2017/08/17 PHP
php使用event扩展的io复用测试的示例
2020/10/20 PHP
用Javascript实现锚点(Anchor)间平滑跳转
2009/09/08 Javascript
jQuery中使用了document和window哪些属性和方法小结
2011/09/13 Javascript
js动画(animate)简单引擎代码示例
2012/12/04 Javascript
利用百度地图JSAPI生成h7n9禽流感分布图实现代码
2013/04/15 Javascript
open 动态修改img的onclick事件示例代码
2013/11/13 Javascript
引用外部脚本时script标签关闭的写法
2014/01/20 Javascript
js实现跨域的几种方法汇总(图片ping、JSONP和CORS)
2015/10/25 Javascript
Javascript中匿名函数的调用与写法实例详解(多种)
2016/01/26 Javascript
Kindeditor在线文本编辑器如何过滤HTML
2016/04/14 Javascript
内容滑动切换效果jquery.hwSlide.js插件封装
2016/07/07 Javascript
webpack配置导致字体图标无法显示的解决方法
2018/03/06 Javascript
在Vue中使用icon 字体图标的方法
2019/06/14 Javascript
vue cli3 调用百度翻译API翻译页面的实现示例
2019/09/13 Javascript
vue-next/runtime-core 源码阅读指南详解
2019/10/25 Javascript
JS eval代码快速解密实例解析
2020/04/23 Javascript
[01:54]TI珍贵瞬间系列(五):压力
2020/08/29 DOTA
scrapy自定义pipeline类实现将采集数据保存到mongodb的方法
2015/04/16 Python
Python爬取网易云音乐上评论火爆的歌曲
2017/01/19 Python
Python 基础教程之包和类的用法
2017/02/23 Python
基于Python socket的端口扫描程序实例代码
2018/02/09 Python
解决Python 命令行执行脚本时,提示导入的包找不到的问题
2019/01/19 Python
Python进程间通信Queue消息队列用法分析
2019/05/22 Python
python 进程的几种创建方式详解
2019/08/29 Python
selenium WebDriverWait类等待机制的实现
2020/03/18 Python
Django数据结果集序列化并展示实现过程
2020/04/22 Python
PyQt5中QSpinBox计数器的实现
2021/01/18 Python
高档奢华时装在线目的地:FORWARD by elyse walker
2017/10/16 全球购物
知名企业招聘广告词大全
2014/03/18 职场文书
四风问题自我剖析材料
2014/10/07 职场文书
2014年销售内勤工作总结
2014/12/01 职场文书