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根据出生日期获得年龄的方法
Mar 31 Python
Python在Console下显示文本进度条的方法
Feb 14 Python
Python实现针对中文排序的方法
May 09 Python
Python中扩展包的安装方法详解
Jun 14 Python
教你用Python写安卓游戏外挂
Jan 11 Python
使用Python读取大文件的方法
Feb 11 Python
pandas 对每一列数据进行标准化的方法
Jun 09 Python
Python使用pyautogui模块实现自动化鼠标和键盘操作示例
Sep 04 Python
基于python实现学生管理系统
Oct 17 Python
快速解释如何使用pandas的inplace参数的使用
Jul 23 Python
Pytorch 扩展Tensor维度、压缩Tensor维度的方法
Sep 09 Python
快速创建python 虚拟环境
Nov 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
php 各种应用乱码问题的解决方法
2010/05/09 PHP
php自定义session示例分享
2014/04/22 PHP
四个PHP非常实用的功能
2015/09/29 PHP
一个简单至极的PHP缓存类代码
2015/10/23 PHP
在Laravel框架里实现发送邮件实例(邮箱验证)
2016/05/20 PHP
关于laravel5.5的定时任务详解(demo)
2019/10/23 PHP
JS实现的简洁纵向滑动菜单(滑动门)效果
2015/10/19 Javascript
jQuery页面刷新(局部、全部)问题分析
2016/01/09 Javascript
webpack配置的最佳实践分享
2017/04/21 Javascript
js 公式编辑器 - 自定义匹配规则 - 带提示下拉框 - 动态获取光标像素坐标
2018/01/04 Javascript
cnpm加速Angular项目创建的方法
2018/09/07 Javascript
微信公众号平台接口开发 获取access_token过程解析
2019/08/14 Javascript
layui: layer.open加载窗体时出现遮罩层的解决方法
2019/09/26 Javascript
Node使用Nodemailer发送邮件的方法实现
2020/02/24 Javascript
vue实例的选项总结
2020/06/09 Javascript
[51:17]Mski vs VGJ.S Supermajor小组赛C组 BO3 第三场 6.3
2018/06/04 DOTA
[44:40]KG vs LGD 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
[01:08:56]DOTA2-DPC中国联赛 正赛 Magma vs LBZS BO3 第一场 2月7日
2021/03/11 DOTA
python self,cls,decorator的理解
2009/07/13 Python
Python2.x版本中基本的中文编码问题解决
2015/10/12 Python
tensorflow获取变量维度信息
2018/03/10 Python
Python常见排序操作示例【字典、列表、指定元素等】
2018/08/15 Python
selenium python 实现基本自动化测试的示例代码
2019/02/25 Python
Python3.5基础之函数的定义与使用实例详解【参数、作用域、递归、重载等】
2019/04/26 Python
基于Python函数和变量名解析
2019/07/19 Python
使用CSS3的appearance属性改变任何元素的浏览器默认风格
2012/12/24 HTML / CSS
CSS3实现水平居中、垂直居中、水平垂直居中的实例代码
2020/02/27 HTML / CSS
HTML5 Canvas实现放大镜效果示例
2020/03/25 HTML / CSS
英国著名的药妆网站:Escentual
2016/07/29 全球购物
婚纱摄影师求职信
2014/03/07 职场文书
工作保证书范文
2014/04/29 职场文书
关于做家务的心得体会
2016/01/23 职场文书
又涨知识了,自律到底多重要?
2019/06/27 职场文书
正确使用MySQL INSERT INTO语句
2021/05/26 MySQL
Javascript的promise,async和await的区别详解
2022/03/24 Javascript
使用python绘制分组对比柱状图
2022/04/21 Python