前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python写一个简单的俄罗斯方块

python写一个简单的俄罗斯方块

作者头像
py3study
发布2020-01-09 11:41:02
6540
发布2020-01-09 11:41:02
举报
文章被收录于专栏:python3

# 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()

运行结构如图所示:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/08/30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档