pygame滞后添加pygame矩形

时间:2018-10-11 05:33:14

标签: python pygame

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

我的问题是它以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)

2 个答案:

答案 0 :(得分:1)

正如@sloth所解释的,有更好的方法可以执行此操作,但是如果您想知道实际的问题是什么,

  • 您没有绘制2000个矩形,而是绘制了10.000个矩形,因为尺寸为100x100

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

只需将支票更改为类似于if b.x+size < display_width and b.y+size < display_height and b.x > 0 and b.y > 0:的东西,便可以提高性能。

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

答案 1 :(得分:0)

而不是每隔一个刻度便将所有这些矩形绘制到屏幕上,而是创建具有噪声一次的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)