7

这是我的第一篇文章。两个月前,我在考虑转行时开始编码,并且正在研究俄罗斯方块的克隆。我已经实现了大部分核心功能,但无法通过 after 循环让游戏不断刷新。

我正在使用 Tkinter 来制作我的 Gui,并正在尝试面向事件的编程。

我的理解是after(Time, Event)fromTkinter应该安排Event在指定的延迟之后发生的任何回调函数Time。我认为代码应该在此之后继续执行后续项目。

我的帧刷新函数 ( game.updateBoard()) 完成了俄罗斯方块工作所需的大部分事件,然后使用 after 调用自身。我在初始化游戏实例时调用它一次。

mainloop()该函数没有继续执行,而是通过无限期地game.updateboard()调用自身。after

我怀疑它没有表现出我认为after的工作方式,即继续执行脚本直到发生指定的延迟。我认为它正在等待回调终止以继续。

我试图找到这方面的资源,但找不到。

如果您有解决此问题、附加代码或一般编码的建议,我很高兴听到这些建议!这是一个学习过程,我很乐意尝试您提出的任何建议。

这是代码的相关部分:

class game():
    def __init__(self): #Set up board and image board
        self.pieces = ["L","J","S","Z","T","O","I"]
        self.board = boardFrame()
        self.root = Tk()
        self.root.title("Tetris")
        self.root.geometry("250x525")

        self.frame = Frame(self.root)

        #set up black and green squares for display
        self.bSquare = "bsquare.gif"
        self.gSquare = "square.gif"
        self.rSquare = "rsquare.gif"
        self.image0 = PhotoImage(file = self.bSquare)
        self.image1 = PhotoImage(file = self.gSquare)
        self.image2 = PhotoImage(file = self.rSquare)

        #get an initial piece to work with
        self.activeBlock = piece(self.pieces[random.randint(0,6)])

        #Tells program to lower block every half second
        self.blockTimer = 0
        self.updateBoard()

        self.root.bind('<KeyPress-Up>', self.turn)
        self.root.bind('<KeyPress-Right>', self.moveR)
        self.root.bind('<KeyPress-Left>', self.moveL)
        self.root.bind('<KeyPress-Down>',self.moveD)
        print("Entering mainloop")
        self.root.mainloop()

    def turn(self, event):
        self.activeBlock.deOccupy(self.board)
        self.activeBlock.turn()
        self.activeBlock.occupy(self.board)
        self.drawGrid(self.board.grid)

    def moveR(self, event):
        self.activeBlock.deOccupy(self.board)
        self.activeBlock.updatePos([1,0], self.board)
        self.activeBlock.occupy(self.board)
        self.drawGrid(self.board.grid)

    def moveL(self, event):
      if self.activeBlock.checkLeft(self.board) == False:
        self.activeBlock.deOccupy(self.board)
        self.activeBlock.updatePos([-1,0], self.board)
        self.activeBlock.occupy(self.board)
        self.drawGrid(self.board.grid)

    def moveD(self, event): #find
        self.activeBlock.deOccupy(self.board)
        self.activeBlock.updatePos([0,-1],self.board)
        if self.activeBlock.checkBottom(self.board) == True:
            self.activeBlock.occupy(self.board)
            self.activeBlock = piece(self.pieces[random.randint(0,6)])
##            self.activeBlock = piece(self.pieces[1])
            print("bottomed")
            self.activeBlock.occupy(self.board)

        self.activeBlock.occupy(self.board)
        self.drawGrid(self.board.grid)

    def drawGrid(self, dGrid):

        #Generate squares to match tetris board
        for widget in self.frame.children.values():
            widget.destroy()

        self.activeBlock.occupy(self.board)

        for x in range(9,-1,-1):
            for y in range(20,-1,-1):
                if self.board.grid[x][y] == 1:
                    self.frame.displayA = Label(self.frame, image=self.image1)
##                    self.frame.displayA.image = self.image1
                    self.frame.displayA.grid(row=21-y, column=x)


                else:
                    self.frame.displayA = Label(self.frame, image = self.image0)
##                    self.frame.displayA.image = self.image0
                    self.frame.displayA.grid(row=21-y, column=x)

        self.frame.displayA = Label(self.frame, image = self.image2)
        self.frame.displayA.grid(row = 21 - self.activeBlock.center[1], column = self.activeBlock.center[0])

        self.frame.grid()

    def updateBoard(self):
        self.blockTimer += 1
        "print updateBoard Loop"

        ## 1)check for keyboard commands
        #1.1 move block by keyboard commands
        #2) see if block has bottomed out, if it has, have it enter itself into the grid and generate a new block.
        if self.activeBlock.checkBottom(self.board) == True:
            self.activeBlock.occupy(self.board)
            self.activeBlock = piece(self.pieces[random.randint(0,6)])
            print("bottomed")
            self.activeBlock.occupy(self.board)

        #2.2 - if block has not bottomed and 50 frames (~.5 seconds) have passed, move the active block down a square after clearing its old space. 
        elif self.blockTimer%12 == 0:
            self.activeBlock.deOccupy(self.board)
            self.activeBlock.updatePos([0,-1], self.board)
            self.activeBlock.occupy(self.board)


    ## 4) check for filled rows
        for y in range(1,21):
            for x in range(10):
                rowFull = True
                if self.board.grid[x][y] == 0:
                    rowFull == False  
            #4.1 if any row is filled, delete it and then move all rows above the deleted row down by one
            if rowFull == True:
                for x2 in range(10):
                    self.board.grid[x2][y] = 0
                    for y2 in range(y+1,21):
                        if self.board.grid[x2][y2] == 1:
                            self.board.grid[x2][y2] = 0
                            self.board.grid[x2][y2-1] = 1

            #4.11 if the row is full and the row above it was full, delete the row again as well as the row above it, and move all rows down by 2
                for x in range(10):
                    rowFull = True
                    if self.board.grid[x][y] == 0:
                        rowFull == False
                        if rowFull == True:
                            for x2 in range(10):
                                try:
                                    self.board.grid[x2][y] = 0
                                    self.board.grid[x2][y+1] = 0
                                except:
                                    pass
                                for y2 in range(y+2,21):
                                    try:
                                        if self.board.grid[x2][y2] == 1:
                                            self.board.grid[x2][y2] = 0
                                            self.board.grid[x2][y2-2] = 1
                                    except:
                                        pass


        #5) if there is a block in the top row, end the game loop
        for x in range(10):
            if self.board.grid[x][20] == 1:
                game = "over"


        #6) update image
        self.activeBlock.occupy(self.board)
        self.drawGrid(self.board.grid)
        self.frame.after(500, self.updateBoard())


Game = game()
4

1 回答 1

17

你想做的self.frame.after(500, self.updateBoard)

这里的区别是微妙的,(self.updateBoard而不是self.updateBoard())。在您的版本中,您将函数的结果传递给after方法,而不是传递函数。这会导致您描述的无限递归。

于 2012-08-20T19:20:00.653 回答