简体   繁体   English

使用Pygame,有没有更快的方法来绘制数百个小方块?

[英]With Pygame, is there a faster way to draw hundreds of small squares?

I'm attempting to make a tile based game, not done anything like this before so I'm learning as I go along. 我正在尝试制作基于图块的游戏,之前没有做过类似的事情,所以我在学习中不断学习。 However, I've got a big problem with speed, and I was wondering if anyone had any solutions/advice. 但是,我在速度方面遇到了一个大问题,我想知道是否有人有任何解决方案/建议。 I tried to separate recalculating bits and the actual drawing, though as you can only move the camera currently, it's got to do both at once, and it's very noticeable how slow it runs if you have a small tilesize and large resolution. 我尝试将重新计算的位和实际图形分开,尽管由于您目前只能移动相机,所以必须一次完成两个操作,而且如果您使用小tilesize和高分辨率,它的运行速度将非常明显。

I thought an idea would be to split it into chunks, so you calculate an x*x area, and instead of checking each tile if it's within the screen bounds, you only check the group of tiles, then somehow cache it the first time it's drawn so you then end up drawing a single image from memory. 我以为可以将其拆分成块,因此您可以计算一个x * x区域,而不是检查每个图块是否在屏幕范围内,而只需检查图块组,然后在第一次时将其缓存绘制,以便最终从内存中绘制单个图像。 However I didn't find anything on that when googling it. 但是我在谷歌搜索时没有发现任何东西。

As to the drawing part, it runs to the effect of: 至于绘图部分,它具有以下效果:

for tile in tile_dict:
    pygame.draw.rect(precalculated stuff)

With the same tilesize as the image below, at 720p it runs at 100fps, and at 1080p it runs at 75fps. 与下图相同的图块大小在720p时以100fps运行,在1080p时以75fps运行。 This is with literally nothing but drawing squares. 实际上,这只是画正方形。 Each block is a slightly different colour, so I can't just draw a bigger square. 每个方块的颜色略有不同,所以我不能只画一个更大的正方形。 I know not to redraw every frame by the way. 我知道不要重画每一帧。

As to the recalculation part, it's a bit longer but still quite easy to understand. 至于重新计算部分,它虽然更长一些,但仍然很容易理解。 I calculate which coordinates would be at the edge of the screen, and use that to build a list of all on screen tiles. 我计算出哪些坐标将位于屏幕边缘,并使用该坐标在屏幕图块上建立所有坐标的列表。 I then delete any tiles that are outside of this area, move the cooordinate to the new location if the tile has moved on screen, and calculate any tiles that have just appeared. 然后,我删除该区域之外的所有图块,如果该图块已在屏幕上移动,则将坐标移动到新位置,然后计算刚刚出现的所有图块。 This runs at about 90fps at 720p, or 45fps at 1080p, which is really not good. 这在720p时约为90fps,在1080p时约为45fps,这确实不好。

def recalculate(self):
    overflow = 2
    x_min = self.cam.x_int + 1 - overflow
    y_min = self.cam.y_int + 1 - overflow
    x_max = self.cam.x_int + int(self.WIDTH / self.tilesize) + overflow
    y_max = self.cam.y_int + int(self.HEIGHT / self.tilesize) + overflow


    self.screen_coordinates = [(x, y) 
                               for x in range(x_min, x_max) 
                               for y in range(y_min, y_max)]


    #Delete the keys that have gone off screen
    del_keys = []
    for key in self.screen_block_data:
        if not x_min < key[0] < x_max or not y_min < key[1] < y_max:
            del_keys.append(key)
    for key in del_keys:
        del self.screen_block_data[key]


    #Rebuild the new list of blocks
    block_data_copy = self.screen_block_data.copy()
    for coordinate in self.screen_coordinates:

        tile_origin = ((coordinate[0] - self.cam.x_int) - self.cam.x_float, 
                       (coordinate[1] - self.cam.y_int) - self.cam.y_float)
        tile_location = tuple(i * self.tilesize for i in tile_origin)

        #Update existing point with new location
        if coordinate in self.screen_block_data:
            self.screen_block_data[coordinate][2] = tile_location
            continue

        block_type = get_tile(coordinate)

        #Generate new point info
        block_hash = quick_hash(*coordinate, offset=self.noise_level)

        #Get colour
        if coordinate in self.game_data.BLOCK_TAG:
            main_colour = CYAN   #in the future, mix this with the main colour
        else:
            main_colour = TILECOLOURS[block_type]
        block_colour = [min(255, max(0, c + block_hash)) for c in main_colour]
        self.screen_block_data[coordinate] = [block_type, 
                                              block_colour, 
                                              tile_location]

I realised in what I wrote above, I probably could cache the info for a 10x10 area or something to cut down on what needs to be done when moving the camera, but that still doesn't get around the problem with drawing. 我在上面写的内容中意识到,我可能可以将信息缓存到10x10的区域,或者减少一些东西来减少移动相机时需要做的事情,但这仍然不能解决绘图问题。

I can upload the full code if anyone wants to try stuff with it (it's split over a few files so probably easier to not paste everything here), but here's a screenshot of how it looks currently for a bit of reference: 如果有人想尝试使用它,我可以上载完整的代码(它分成几个文件,因此可能更容易在这里不粘贴所有内容),但是下面是它的屏幕快照,以供参考:

在此处输入图片说明

To increase the speed of drawing the small squares, you can draw them onto non-screen surface (any pygame surface that will be big enough to hold all the squares) and then blit this surface on the screen with correct coordinates. 为了提高绘制小方块的速度,您可以将它们绘制到非屏幕表面(任何足以容纳所有正方形的pygame表面)上,然后使用正确的坐标将该表面涂抹在屏幕上。 This way you won't need to check if any squares are outside the screen and it will be only necessary to provide inverted camera (viewpoint) coordinates (If camera position is [50,20] then you should blit the surface with tiles onto [-50,-20]). 这样,您无需检查屏幕外是否有任何正方形,只需提供倒置的摄像机(视点)坐标(如果摄像机位置为[50,20],则应在[ -50,-20])。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM