我想创建一个基于 block 物理的游戏,但是 fps 下降得非常快。 我尝试尽可能地优化它,但它的 fps 仍然相当低(200 block 给我大约 20 fps)。有谁知道如何优化我的 block 游戏?我本来打算添加更多内容,但看到这个问题我可能会放弃。
这是我的代码:
from tkinter import *
import math
import random
import time
master = Tk()
w = Canvas(master,width=600,height=600)
w.pack()
tileSize = 20
def randomColor():
r = math.floor(random.random() * 255)
g = math.floor(random.random() * 255)
b = math.floor(random.random() * 255)
return '#%02x%02x%02x' % (r, g, b)
class newElement:
def __init__(self,x,y):
x = math.floor(x/tileSize) * tileSize
y = math.floor(y/tileSize) * tileSize
self.x = x
self.y = y
self.vx = 0
self.vy = 0
self.width = tileSize
self.height = tileSize
self.id = random.random()
self.color = randomColor()
elements = []
def mouse(event):
global mouseX,mouseY
mouseX,mouseY = event.x,event.y
canPlace = True
for y in range(0,len(elements)):
e = elements[y]
dx = e.x + e.width/2 - mouseX
dy = e.y + e.height/2 - mouseY
if math.sqrt(dx*dx+dy*dy) < 20:
canPlace = False
break
if canPlace:
elements.append(newElement(mouseX,mouseY))
mouseX = 0
mouseY = 0
w.bind("<B1-Motion>",mouse)
elements.append(newElement(300,50))
elements.append(newElement(300,100))
def collision(rect1,rect2):
return rect1.x < rect2.x + rect2.width and rect1.x + rect1.width > rect2.x and rect1.y < rect2.y + rect2.height and rect1.height + rect1.y > rect2.y
def distance(rect1,rect2):
dx = rect1.x - rect2.x
dy = rect2.y - rect2.y
return math.sqrt(dx*dx+dy*dy)
lastCall = time.time()
def engine():
global lastCall
w.delete("all")
w.create_line(0,590,600,590)
for i in range(0,len(elements)):
e = elements[i]
gravity = 0.1
e.vy += gravity
e.x += e.vx
e.y += e.vy
if e.y + e.height >= 590:
e.y = 590-e.height
e.vy = 0
for x in range(0,len(elements)):
e1 = elements[x]
if e.id == e1.id or distance(e,e1) > 14.14:
continue
col = collision(e,e1)
if col:
e.y = e1.y - e1.height
e.vy = 0
w.create_rectangle(e.x,e.y,e.x+e.width,e.y+e.height,fill=e.color)
w.create_text(10,10,anchor=NW,text=len(elements))
fps = 60
if time.time() - lastCall != 0:
fps = round(1/(time.time() - lastCall))
w.create_text(600,10,anchor=NE,text=fps)
lastCall = time.time()
master.after(16,engine)
engine()
mainloop()
最佳答案
Tkinter 能够为这样的简单程序实现 60fps,但性能会根据您选择的算法而降低。我概述了您可以采取的几项措施来提高代码的性能。
当我编写一个与您的程序类似的程序但进行了下面概述的更改时,我能够在包含超过 1000 个项目的情况下获得 60fps 的速度。
不要删除和重画
最大的问题是您每秒要多次删除和创建矩形。这是非常低效的。更糟糕的是,一旦您创建了数千个项目,即使您后来删除了它们, Canvas 也会出现性能问题。我已经成功地为数千个项目制作了动画,但如果您创建了数万个项目,它可能会开始变得缓慢。
您应该做的是创建一次项目,然后为每个项目提供一个 move
方法,以便移动现有项目而不是删除然后重新创建它。
不要移动不需要移动的项目
第二个问题是您在每一帧中移动所有对象,即使它们的速度为零。不需要对不会移动的物体进行计算。
让 tkinter 为您找到碰撞
第三个问题是您查找冲突的算法效率极低。如果您有 300 个对象,则需要进行 300x300 的比较。例如,您将检查项目 1 是否与项目 2 碰撞,然后是项目 3,然后是项目 4,等等。然后,您检查项目 2 是否与项目 1、项目 3、项目 4 等发生碰撞。因为您已经已经确定项目 1 和 2 是否发生碰撞,没有理由查看项目 2 和 1 是否发生碰撞。另外,由于项目总是直接向下移动,因此您实际上只需要检查与当前项目正下方的项目的碰撞。
您可以通过让 tkinter 为您完成工作来解决碰撞问题。给定一个对象,您可以获得与 find_overlapping 重叠的所有对象的列表。 Canvas 的方法。这可能比将每个对象与每个对象进行比较要快几个数量级,因为它是由 tkinter 在内部 Canvas 数据结构上内部完成的(即:它是使用 C 代码而不是 Python 代码)。
关于Python tkinter 性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47556992/