問題描述
這是我的第一篇文章.兩個月前,我在考慮轉行時開始編碼,并且正在研究俄羅斯方塊的克隆.我已經實現了大部分核心功能,但無法通過 after 循環讓游戲不斷刷新.
This is my first post. I started coding when considering a career swap two months ago and am working on a Tetris clone. I've implemented most of the core features, but cannot get the game to refresh continually with an after loop.
我正在使用 Tkinter 來制作我的 Gui,并且正在嘗試面向事件的編程.
I'm using Tkinter to produce my Gui and am trying out event oriented programming.
我的理解是 Tkinter
中的 after(Time, Event)
應該安排在指定的延遲之后發生的任何 Event
回調函數按時間
.我認為代碼應該在此之后繼續執行后續項目.
My understanding is that after(Time, Event)
from Tkinter
should schedule whatever the Event
callback function is to occur after a delay specified by Time
. I think that the code is supposed to continue executing subsequent items after this.
我的幀刷新函數 (game.updateBoard()
) 完成了俄羅斯方塊工作所需的大部分事件,然后使用 after 調用自身.我在初始化游戲實例時調用它一次.
My frame refresh function (game.updateBoard()
) does most of the necessary events for tetris to work, then calls itself using after. I call it once when initializing an instance of the game.
game.updateboard()
函數不是繼續執行 mainloop()
,而是通過 after
無限期地調用自身.
Instead of proceeding to mainloop()
, the game.updateboard()
function calls itself via after
indefinitely.
我懷疑它的行為不像我認為的 after
那樣繼續執行腳本,直到發生指定的延遲.我認為它正在等待回調終止以繼續.
I suspect that it is not behaving how I thought after
worked which would be to continue to execute the script until the specified delay occurs. I think it is waiting for the callback to terminate to continue.
我試圖找到這方面的資源,但找不到.
I tried to find a resource on this but could not.
如果您有解決此問題、附加代碼或一般編碼的建議,我很高興聽到這些建議!這是一個學習過程,我很樂意嘗試您提出的任何建議.
If you have suggestions for fixing this question, the attached code, or for coding in general, I am very happy to hear them! This is a learning process and I'll gladly try pretty much anything you suggest.
以下是代碼的相關部分:
Here is the relevant portion of the code:
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()
推薦答案
你想做self.frame.after(500, self.updateBoard)
.
這里的區別很微妙,(self.updateBoard
而不是 self.updateBoard()
).在您的版本中,您將函數的結果 傳遞給after
方法,而不是傳遞函數.這會導致您描述的無限遞歸.
The difference here is subtle, (self.updateBoard
instead of self.updateBoard()
). In your version, you're passing the result of your function to the after
method instead of passing the function. This results in the infinite recursion that you described.
這篇關于“之后"無限循環:從不進入主循環的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!