我用Tkinter写了一个Python程序,让球在屏幕上反弹。除了一个问题外,它的效果很好:当球移动时,球的最外边缘会闪烁。
我知道Tkinter自动进行双重缓冲,所以我认为我不应该有撕裂问题。我不确定错误来自哪里。关于如何摆脱它的任何想法?
代码如下。以下是它的要点:类Ball扩展Tk并在程序运行时创建。它设置游戏,将其封装在GModel中。然后GModel使用run()运行游戏,只是反复循环,调用update()。
import threading
from time import sleep, clock
from tkinter import *
from tkinter import ttk
SPEED = 150 # Pixels per second
WIDTH = 400
HEIGHT = 500
RAD = 25
PAUSE = 0 # Time added between frames. Slows things down if necessary
class GModel:
# Contains the game data.
def __init__(self, can):
# can is Canvas to draw on
self.can = can
self.circ = can.create_oval(0,0, 2*RAD, 2*RAD)
# Position and velocity of the ball
self.x, self.y = RAD, RAD
self.dx, self.dy = SPEED, SPEED
# Ball is moving?
self.is_running = True
def update(self, elapsed_time):
# Updates the dynamic game variables. elapsed_time is in seconds.
change_x = self.dx * elapsed_time
change_y = self.dy * elapsed_time
self.can.move(self.circ, change_x, change_y)
self.x += change_x
self.y += change_y
self.resolve_collisions()
def resolve_collisions(self):
# If the ball goes off the edge, put it back and reverse velocity
if self.x - RAD < 0:
self.x = RAD
self.dx = SPEED
elif self.x + RAD > WIDTH:
self.x = WIDTH - RAD
self.dx = -SPEED
if self.y - RAD < 0:
self.y = RAD
self.dy = SPEED
elif self.y + RAD > HEIGHT:
self.y = HEIGHT - RAD
self.dy = -SPEED
def end_game(self):
self.is_running = False
def run(self):
last_time = 0.0
while self.is_running:
# Get number of seconds since last iteration of this loop
this_time = clock()
elapsed_time = this_time - last_time
last_time = this_time
try: # Use this here in case the window gets X'd while t still runs
self.update(elapsed_time)
except:
self.is_running = False
if (PAUSE > 0):
sleep(PAUSE) # Slow things down if necessary
class Ball(Tk):
def __init__(self):
Tk.__init__(self)
self.can = Canvas(self, width=WIDTH, height=HEIGHT)
self.can.grid(row=0, column=0, sticky=(N, W, E, S))
self.gm = GModel(self.can)
def mainloop(self):
t = threading.Thread(target=self.gm.run, daemon=True)
t.start()
Tk.mainloop(self)
def main():
Ball().mainloop()
if __name__ == "__main__":
main()