Tkinter画布的速度/滞后问题

时间:2016-05-05 21:34:25

标签: python-3.x tkinter

我在两个程序中遇到了类似的问题。

在" Pong"程序,球随机滞后,使其难以发挥。

在"突围"程序,我不能让球以良好的速度移动。

睡眠(0.001)太慢,没有睡眠声明太快。我最好的解决方法是垃圾邮件打印("")创建延迟(第75/76行),但这有时只能起作用。我怀疑问题是我在Tkinter中使用Threads,我听说这不是一个好主意,但是还有什么可以做的。

另外,是的,我知道我应该使用Pygame代替这些,但我主要在学校编程拒绝安装Pygame。

突围:

from tkinter import *
from tkinter import messagebox
from random import choice, randint
from time import sleep,time
from threading import Thread
import sys

HEIGHT = 500
WIDTH = 1000

BATWIDTH = 200
BLOCKWIDTH = 80
BLOCKHEIGHT = 40

ballLaunched = False

root = Tk()
root.title("Breakout")
root.resizable(0,0)
root.config(bg = "#000000")

def main():
    global canvas, bat, ball, direction, ballCoord, blocks, lives, livesText, board

    board = Frame(root)
    board.grid()
    board.config(bg = "#000000")

    canvas = Canvas(board, width=WIDTH, height=HEIGHT, bg = "#262626")
    canvas.grid()

    bat = canvas.create_rectangle(0,0,0,0, fill="red")

    direction = [1,1]
    ball = canvas.create_oval(0,0,0,0, fill="#FFFFFF", tags = "Ball")

    lives = 3
    livesText = canvas.create_text(33,13,text="Lives: "+str(lives),fill="#FFFFFF",font="helvetica")


    #Makes all the blocks
    blocks = []

    #Create the blocks
    for i in range(6):
        for j in range(int(WIDTH/BLOCKWIDTH)):
            topX = 5 + (BLOCKWIDTH*j) + (WIDTH%BLOCKWIDTH)/2
            topY = BLOCKHEIGHT*2 + (BLOCKHEIGHT*i)
            block = canvas.create_rectangle(topX,topY,topX+BLOCKWIDTH,topY+BLOCKHEIGHT, tags = "Block")

            if i == 0:
                canvas.itemconfig(block,fill = "#ff0000")
            elif i == 1:
                canvas.itemconfig(block,fill = "#ff8000")
            elif i == 2:
                canvas.itemconfig(block,fill = "#ffff00")
            elif i == 3:
                canvas.itemconfig(block,fill = "#80ff00")
            elif i == 4:
                canvas.itemconfig(block,fill = "#00ffff")
            elif i == 5:
                canvas.itemconfig(block,fill = "#0080ff")
            blocks.append(block)






def update():
    global direction, lives
    ballCoord = {"topX":mouseXStart-20/2,"topY":400,"bottomX":mouseXStart+20/2,"bottomY":420}

    while True:
        #sleep(1/1000)
        print()

        ballCoord["topX"]+=direction[0] 
        ballCoord["topY"]+=direction[1]
        ballCoord["bottomX"]+=direction[0]
        ballCoord["bottomY"]+=direction[1]

        canvas.coords(ball,ballCoord["topX"],ballCoord["topY"],ballCoord["bottomX"],ballCoord["bottomY"])
        if len((canvas.find_overlapping(ballCoord["topX"]-1,ballCoord["topY"]-1,ballCoord["bottomX"]+1,ballCoord["bottomY"]+1))) >= 2 and ballCoord["bottomY"] <= 400 and ballCoord["topY"] >= 20:
            for i in blocks:
                blockTopX = canvas.bbox(i)[0]
                blockTopY = canvas.bbox(i)[1]
                blockBottomX = canvas.bbox(i)[2]
                blockBottomY = canvas.bbox(i)[3]
                for j in canvas.find_overlapping(canvas.bbox(i)[0],canvas.bbox(i)[1],canvas.bbox(i)[2],canvas.bbox(i)[3]):
                    if "Ball" in canvas.gettags(j):
                        #Moving Top Left
                        if direction == [-1,-1]:
                            if ballCoord["topY"] == blockBottomY:
                                direction = [-1,1]
                            elif ballCoord["topX"] == blockBottomX:
                                direction = [1,-1]
                            canvas.delete(i)
                            blocks.remove(i)

                        #Moving Top Right
                        elif direction == [1,-1]:
                            if ballCoord["topY"] == blockBottomY:
                                direction = [1,1]
                            elif ballCoord["bottomX"] == blockTopX:
                                direction = [-1,-1]
                            canvas.delete(i)
                            blocks.remove(i)

                        #Moving Bottom Right
                        elif direction == [1,1]:
                            if ballCoord["bottomY"] == blockTopY:
                                direction = [1,-1]
                            elif ballCoord["bottomX"] == blockTopX:
                                direction = [-1,1]
                            canvas.delete(i)
                            blocks.remove(i)

                        #Moving Bottom Left
                        elif direction == [-1,1]:
                            if ballCoord["bottomY"] == blockTopY:
                                direction = [-1,-1]
                            elif ballCoord["topX"] == blockBottomX:
                                direction = [1,1]
                            canvas.delete(i)
                            blocks.remove(i)


        #Bat Collision
        try:
            #Left side
            if len(canvas.find_overlapping(mouseX-BATWIDTH/2,450,mouseX, 470)) == 2:
                    direction = [-1,-1]
            #Right side
            if len(canvas.find_overlapping(mouseX,450,mouseX+BATWIDTH/2, 470)) == 2:
                    direction = [1,-1]
        except NameError:
            pass


        #Right Wall Collision
        if ballCoord["bottomX"] >= WIDTH:
            if direction == [1,-1]:
                direction = [-1,-1]
            if direction == [1,1]:
                direction = [-1,1]


        #Roof Collision                
        if ballCoord["topY"] <= 0:
            if direction == [1,-1]:
                direction = [1,1]
            if direction == [-1,-1]:
                direction = [-1,1]


        #Left Wall Collision
        if ballCoord["topX"] <= 0:
            if direction == [-1,-1]:
                direction = [1,-1]
            if direction == [-1,1]:
                direction = [1,1]

        #Offscreen
        if ballCoord["topY"] >= HEIGHT:
            global ballLaunched
            lives -= 1
            canvas.itemconfig(livesText,text="Lives: "+str(lives))
            sleep(1)
            ballLaunched = False
            if lives <= 0:
                gameOver()
            break

def moveBat(event):
    global mouseX,mouseY   
    mouseX, mouseY = event.x, event.y
    #if mouseX >= 100 and mouseX <= 900:
    canvas.coords(bat, mouseX-BATWIDTH/2, 450,  mouseX+BATWIDTH/2, 470)
    try:
        if not ballLaunched:
            canvas.coords(ball, mouseX-20/2, 400,  mouseX+20/2, 420)
    except NameError:
        canvas.coords(ball, mouseX-20/2, 400,  mouseX+20/2, 420)

def launchBall(event):
    global ballLaunched, mouseXStart
    if not ballLaunched:
        ballLaunched = True
        mouseXStart = mouseX
        Thread(target=update).start()


def gameOver():
    if messagebox.askquestion("Game Over","Play Again?") == "yes":
        board.destroy()
        main()
    else:
        root.destroy()
        sys.exit()



main()
root.bind("<Motion>", moveBat)
root.bind("<Button-1>", launchBall)
root.mainloop()

Pong(感谢Bryan Oakley的基础类我复制了一点):

from tkinter import *
from tkinter import messagebox
from random import choice, randint,uniform
from time import sleep,time
from threading import Thread
import sys

HEIGHT = 750
WIDTH = 1000

BATHEIGHT = 100
BATWIDTH = 20        


class Board:
    def __init__(self):
        self.pressed = {}
        self._create_ui()
        self.ballLaunched = False

    def start(self):
        self._animate()
        self.root.mainloop()

    def _create_ui(self):
        self.root = Tk()
        self.root.title("Pong")
        self.root.resizable(0,0)
        self.root.config(bg = "#262626")

        self.canvas = Canvas(width=WIDTH, height=HEIGHT,bg = "#262626")
        self.canvas.grid()

        self.p1 = Paddle(self.canvas, tag="p1", x=50, y=HEIGHT/2)
        self.p2 = Paddle(self.canvas, tag="p2", x=WIDTH-50, y=HEIGHT/2)

        self.ball = Ball(self.canvas, tag="Ball", x=WIDTH/2, y=HEIGHT/2,direction=choice([[1,1],[-1,-1],[1,-1],[-1,1]]),paddleLeft = self.p1,paddleRight = self.p2)

        height = 0
        for i in range(29):
            height += 20
            self.canvas.create_rectangle((WIDTH/2)-5,height,(WIDTH/2)+5,height+10,fill="white",width=0)
            height += 5

        global leftScore,rightScore,leftScoreText,rightScoreText
        leftScore,rightScore = 0,0
        leftScoreText = self.canvas.create_text((WIDTH/2)-100,75, text = leftScore, font=("System",75), fill= "white")
        rightScoreText = self.canvas.create_text((WIDTH/2)+100,75, text = rightScore, font=("System",75), fill= "white")

        self.startText = self.canvas.create_text(WIDTH/2,(HEIGHT/2)-40,text="Press <Space> To Start", font=("System",20), fill= "white")

        self._set_bindings()                

    def _animate(self):
        if self.pressed["w"]: self.p1.move_up()
        if self.pressed["s"]: self.p1.move_down()
        if self.pressed["o"]: self.p2.move_up()
        if self.pressed["l"]: self.p2.move_down()

        self.p1.redraw()
        self.p2.redraw()
        self.root.after(10, self._animate)

    def _set_bindings(self):
        for char in ["w","s","o", "l", " "]:
            self.root.bind("<KeyPress-%s>" % char, self._pressed)
            self.root.bind("<KeyRelease-%s>" % char, self._released)
            self.pressed[char] = False

    def _pressed(self, event):
        self.pressed[event.char] = True

    def _released(self, event):
        if self.pressed[" "] and not self.ballLaunched:
            self.canvas.delete(self.startText)
            self.ballLaunched = True
            Thread(target=self.ball.redraw).start()

        self.pressed[event.char] = False


class Paddle():
    def __init__(self, canvas, tag, x=0, y=0):
        self.canvas = canvas
        self.tag = tag
        self.x = x
        self.y = y

        self.bat = self.canvas.create_rectangle(self.x-BATWIDTH/2,self.y - BATHEIGHT/2,self.x + BATWIDTH/2,self.y + BATHEIGHT/2,tags=self.tag, fill="white",width=0)

        self.redraw()

    def move_up(self):
        self.y = max(self.y - 10, (BATHEIGHT/2)+3)

    def move_down(self):
        self.y = min(self.y + 10, HEIGHT-BATHEIGHT/2)

    def redraw(self):
        self.x0 = self.x - BATWIDTH/2
        self.x1 = self.x + BATWIDTH/2
        self.y0 = self.y - BATHEIGHT/2
        self.y1 = self.y + BATHEIGHT/2

        self.canvas.coords(self.bat,self.x0,self.y0,self.x1,self.y1)


class Ball():
    def __init__(self,canvas,tag,x=0,y=0,direction=[1,1],paddleLeft=0,paddleRight=0):
        self.canvas = canvas
        self.tag = tag
        self.x = x
        self.y = y
        self.direction = direction
        self.paddleLeft = paddleLeft
        self.paddleRight = paddleRight
        self.speed = 0.5
        self.ball = self.canvas.create_rectangle(self.x - 20/2,self.y - 20/2 ,self.x + 20/2,self.y + 20/2,tags=self.tag, fill="white",width=0)

    def redraw(self):
        while True:
            #sleep(1/1000)
            #print()
            self.x0 = self.x - 20/2 
            self.x1 = self.x + 20/2 
            self.y0 = self.y - 20/2 
            self.y1 = self.y + 20/2

            self.canvas.coords(self.ball,self.x0,self.y0,self.x1,self.y1)           

            self.move()
            if self.checkCollision() == "Top":
                if self.direction == [1,-1]: self.direction = [1,1]
                elif self.direction == [-1,-1]: self.direction = [-1,1]
            if self.checkCollision() == "Bottom":
                if self.direction == [1,1]: self.direction = [1,-1]
                elif self.direction == [-1,1]: self.direction = [-1,-1]
            if self.checkCollision() == "Left":
                if self.direction == [-1,1]: self.direction = [1,1]
                elif self.direction == [-1,-1]: self.direction = [1,-1]
            if self.checkCollision() == "Right":
                if self.direction == [1,-1]: self.direction = [-1,-1]
                elif self.direction == [1,1]: self.direction = [-1,1]

            global leftScore,rightScore,leftScoreText,rightScoreText  
            if self.checkCollision() == "Right Scored":
                rightScore += 1
                self.canvas.itemconfig(rightScoreText ,text=rightScore)
                self.resetBall()

            if self.checkCollision() == "Left Scored":
                leftScore += 1
                self.canvas.itemconfig(leftScoreText ,text=leftScore)
                self.resetBall()



    def move(self):
        self.x += self.direction[0] * self.speed
        self.y += self.direction[1] * self.speed

    def checkCollision(self):
        if self.y0 <= 0: return "Top"
        if self.y1 >= HEIGHT: return "Bottom"
        if len(self.canvas.find_overlapping(self.x0,self.y0,self.x1,self.y1)) >= 2 and self.x0 >= WIDTH-100: return "Right"
        if len(self.canvas.find_overlapping(self.x0,self.y0,self.x1,self.y1)) >= 2 and self.x0 <= 100: return "Left"

        if self.x < 0: return "Right Scored"
        if self.x > WIDTH: return "Left Scored"

    def resetBall(self):
        sleep(1)
        self.x,self.y = WIDTH/2,HEIGHT/2
        self.direction=choice([[1,1],[-1,-1],[1,-1],[-1,1]])





b = Board()
b.start()

0 个答案:

没有答案