我在两个程序中遇到了类似的问题。
在" 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()