python – 如何在Pygame表面实现泛洪填充

我想知道一个填充Pygame表面部分的好方法.

我想要的最好的例子是油漆桶在MS Paint中的工作方式.

例如,如果在白色表面上有一个黑色圆圈,我想填充圆圈内的白色(或任何形状).

为了让你知道我正在做什么,我正在制作一个像素艺术工具,我正在研究一个类似于MS Paint的桶的功能. (观看次数:http://imgur.com/a/ogtPV)

我已经尝试使用Surface.get_at()和Surface.set_at()来填充,但是一旦你想要填充一个区域的100×100像素,它就会滞后太多.

我也对任何其他不滞后的方法持开放态度.

最佳答案 我发现一种方法,对于100×100区域大约需要60 ms,对于1000×1000区域大约需要2000 ms.代码中的解释.

import random
import pygame
pygame.init()

screen = pygame.display.set_mode((1024, 640))
clock = pygame.time.Clock()

image = pygame.image.load('delete_image.png').convert()


def fill(surface, position, fill_color):
    fill_color = surface.map_rgb(fill_color)  # Convert the color to mapped integer value.
    surf_array = pygame.surfarray.pixels2d(surface)  # Create an array from the surface.
    current_color = surf_array[position]  # Get the mapped integer color value.

    # 'frontier' is a list where we put the pixels that's we haven't checked. Imagine that we first check one pixel and 
    # then expand like rings on the water. 'frontier' are the pixels on the edge of the pool of pixels we have checked.
    #
    # During each loop we get the position of a pixel. If that pixel contains the same color as the ones we've checked
    # we paint it with our 'fill_color' and put all its neighbours into the 'frontier' list. If not, we check the next
    # one in our list, until it's empty.

    frontier = [position]
    while len(frontier) > 0:
        x, y = frontier.pop()
        try:  # Add a try-except block in case the position is outside the surface.
            if surf_array[x, y] != current_color:
                continue
        except IndexError:
            continue
        surf_array[x, y] = fill_color
        # Then we append the neighbours of the pixel in the current position to our 'frontier' list.
        frontier.append((x + 1, y))  # Right.
        frontier.append((x - 1, y))  # Left.
        frontier.append((x, y + 1))  # Down.
        frontier.append((x, y - 1))  # Up.

    pygame.surfarray.blit_array(surface, surf_array)


while True:
    clock.tick(30)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            quit()
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                color = random.choice(tuple(pygame.color.THECOLORS.values()))
                print('Running')
                time = pygame.time.get_ticks()
                fill(image, event.pos, color)
                print('Finished in {} ms'.format(pygame.time.get_ticks() - time))

    screen.blit(image, (0, 0))
    pygame.display.update()

这是我试验的图像(如果你试图出售图像,我将获得收入):
《python – 如何在Pygame表面实现泛洪填充》

点赞