【问题标题】:Pygame lags with pygame rectangles addedPygame 滞后添加了 pygame 矩形
【发布时间】:2018-10-11 05:33:14
【问题描述】:

我正在运行一个 python 游戏,每帧在屏幕上绘制大约 2k 个矩形。

我遇到的问题是它以 12 fps 运行,我不知道如何解决这个问题。当我删除所有矩形时,它会变为 100 fps。我不会一次渲染所有这些,但只有相机当前可以看到的那些。如何解决这个延迟峰值问题,是因为我使用了 pygame 矩形还是因为我使用错误?

这是代码

import pygame
black = (0,0,0)
pygame.init()
gameDisplay = pygame.display.set_mode((0,0),pygame.FULLSCREEN)
gameDisplay.fill(black)
gameDisplay.convert()
clock = pygame.time.Clock()
display_width = 1920
display_height = 1080

from opensimplex import OpenSimplex
tmp = OpenSimplex()

dimensions = [100,100]
size = 40

def mapping(x):
    y = (x + 1) * 10 + 40
    return y

class GroundCell:
    def __init__(self,x,y,dim):
        self.x = x
        self.y = y
        self.dim = dim

tempcells = []
allCells = []

for a in range(0,dimensions[0]):
    tempcells = []
    for b in range(0,dimensions[1]):
        tempcells.append(GroundCell(a*size,b*size,mapping(tmp.noise2d(a*0.11,b*0.11))))
    allCells.append(tempcells)

font = pygame.font.Font("freesansbold.ttf", 20)
while True:
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                pygame.quit()
                quit()
    for a in allCells:
        for b in a:
            if b.x in range(0,display_width) \
                and b.y in range(0,display_height) or\
                b.x+size in range(0,display_width) \
                and b.y+size in range(0,display_height) :
                pygame.draw.rect(gameDisplay,(b.dim,b.dim,b.dim),(b.x,b.y,size,size))

    fps = font.render('FPS: ' + str(int(clock.get_fps())), 1, (0, 0, 0))
    gameDisplay.blit(fps, (20, 20))

    pygame.display.update()
    clock.tick(120)
    gameDisplay.fill(black)

【问题讨论】:

  • 听起来你需要做一些分析。至于您是否正确使用了矩形 - 没有看到 minimal reproducible example 就很难说。
  • 添加示例代码

标签: python pygame


【解决方案1】:

不是每次滴答声都将所有这些矩形绘制到屏幕上,而是创建一个带有噪声一次的 Surface,然后重复使用它。

还有一些注意事项:

文本渲染很昂贵。如果您使用大量文本渲染,最好缓存Font.render 创建的表面。请注意,pygame 中还有新的freetype 模块,它在各方面都优于font 模块。

你检查一个矩形是否在屏幕内很奇怪。你可以只使用if 0 < b.x < display_width ... 之类的东西,甚至可以使用pygame 的Rect 类,它提供了像contains() 这样的好方法。

从任意数据创建 Surface 的一种快速的好方法是使用 numpy 和 pygame 的 surfarray 模块。不要被吓倒,它并不难使用。

这是一个基于您的代码的运行示例:

import pygame
import numpy as np

black = (0,0,0)
pygame.init()
display_width = 1000
display_height = 1000
gameDisplay = pygame.display.set_mode((display_width, display_height))
gameDisplay.fill(black)
clock = pygame.time.Clock()

from opensimplex import OpenSimplex
tmp = OpenSimplex()

dimensions = [100,100]
size = 16

def mapping(x):
    y = (x + 1) * 10 + 40
    return y

# create an 2d array from the noise
def get_array():
    rgbarray = np.zeros((dimensions[0], dimensions[1]))
    for x in range(dimensions[0]):
        for y in range(dimensions[1]):
            c = int(mapping(tmp.noise2d(x*0.11, y*0.11)))
            # simple way to convert the color value to all three (r,g,b) channels
            rgbarray[x, y] = c | c << 8 | c << 16 
    return rgbarray

# create the array and copy it into a Surface
data = get_array()
surface = pygame.Surface((dimensions[0], dimensions[1]))
pygame.surfarray.blit_array(surface, data)

# scale the Surface to the desired size
scaled = pygame.transform.scale(surface, (dimensions[0]*size, dimensions[1]*size))

# simple way to cache font rendering
font = pygame.font.Font("freesansbold.ttf", 20)
cache = {}
def render(text):
    if not text in cache:
        cache[text] = font.render(text, 1, (0, 0, 0))
    return cache[text]

x = 0
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                running = False

    x-=1
    if x < -1000:
        x = 0

    gameDisplay.blit(scaled, (x, 0))
    fps = render('FPS: ' + str(int(clock.get_fps())))
    gameDisplay.blit(fps, (20, 20))
    pygame.display.update()
    clock.tick(120)

【讨论】:

    【解决方案2】:

    正如@sloth 解释的那样,有更好的方法来做同样的事情,但如果你想知道实际问题是什么:

    • 您不是在绘制 2000 个矩形,而是在绘制其中的 10.000 个,因为您的尺寸是 100x100

    • 您正在检查矩形是否以性能最差的方式可见。只需检查如果您离开检查并且不绘制矩形会发生什么。您会看到性能有所提高,但距离 120fps 还差得很远。这是因为对于每个 矩形,您会生成一个从0 到屏幕宽度的数字列表和另一个从零到屏幕高度的列表。你也这样做了两次。这意味着,在1920x1080 屏幕上:(1920 * 10000) + (1920 * 10000) + (1080 * 10000) + (1080*10000) = 60000000。所以,有 60 百万张支票。如果您有 120fps,这意味着每秒 6000 万 * 120 = 72 次十亿次检查。

    只需将检查更改为类似于if b.x+size &lt; display_width and b.y+size &lt; display_height and b.x &gt; 0 and b.y &gt; 0: 的内容即可提高性能。

    也就是说,它仍然是 10000 个矩形,它仍然是 120fps,这意味着每秒 1200000 个矩形,基本上没有硬件加速和高级语言。不要指望顶级性能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-02
      • 2020-04-06
      • 2017-07-18
      • 2015-03-17
      • 1970-01-01
      相关资源
      最近更新 更多