【问题标题】:Fill the area of intersection of two Circles in Pygame在 Pygame 中填充两个圆的交集区域
【发布时间】:2023-03-24 19:29:01
【问题描述】:

我正在做一个 pygame 项目,但遇到了问题。我有两个圆圈 A 和 B,如下所示。重叠的现在我只想填充两个圆圈共有的圆圈的一部分。有什么方法可以实现吗?

我知道我可以用红色填充圆 B,用白色填充圆 A,但是有一个特定区域,圆 A 超出了该区域。所以我无法实现。

这张图片中提到了圆圈和填充位置的图像:

【问题讨论】:

    标签: python pygame


    【解决方案1】:

    使用每个像素的 alpha (pygame.SRCALPHA) 创建 2 个 pygame.Surface 对象:

    surf1 = pygame.Surface((500, 500), pygame.SRCALPHA)
    surf2 = pygame.Surface((500, 500), pygame.SRCALPHA)
    

    定义两个圆的中心点和半径:

    pos1, rad1 = (250, 200), 100
    pos2, rad2 = (250, 250), 80
    

    在两个表面上用相同的颜色绘制圆圈:

    pygame.draw.circle(surf1, (255, 0, 0, 255), pos1, rad1)
    pygame.draw.circle(surf2, (255, 0, 0, 255), pos2, rad2)
    

    使用混合模式pygame.BLEND_RGBA_MIN 将一个表面混合到另一个表面:

    surf1.blit(surf2, (0, 0), special_flags = pygame.BLEND_RGBA_MIN)
    

    此时surf1包含了2个圆的交集区域。

    要获得外部部分,还需要另一个步骤。在surf2 上混合surf1,使用混合模式pygame.BLEND_RGBA_MIN

    surf2.blit(surf1, (0, 0), special_flags = pygame.BLEND_RGBA_SUB)
    

    现在surf2 包含 circle B 的部分,如果 circle A 被减去,则剩下的部分:


    最小示例: repl.it/@Rabbid76/PyGame-CircleIntersection

    import pygame
    
    pygame.init()
    window = pygame.display.set_mode((500, 500))
    clock = pygame.time.Clock()
    
    pos1, rad1 = (250, 200), 100
    pos2, rad2 = (250, 250), 80
    
    surf1 = pygame.Surface((500, 500), pygame.SRCALPHA)
    surf2 = pygame.Surface((500, 500), pygame.SRCALPHA)
    
    pygame.draw.circle(surf1, (255, 0, 0, 255), pos1, rad1)
    pygame.draw.circle(surf2, (255, 0, 0, 255), pos2, rad2)
    
    surf1.blit(surf2, (0, 0), special_flags = pygame.BLEND_RGBA_MIN)
    surf2.blit(surf1, (0, 0), special_flags = pygame.BLEND_RGBA_SUB)
    
    run = True
    while run:
        clock.tick(60)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
            if event.type == pygame.KEYDOWN:
                print(pygame.key.name(event.key))
     
        window.fill((255, 255, 255))
    
        window.blit(surf2, (0, 0))     
        pygame.draw.circle(window, (128, 128, 128), pos1, rad1+1, 3)
        pygame.draw.circle(window, (128, 128, 128), pos2, rad2+1, 3)
    
        pygame.display.flip()
    

    【讨论】:

    • 这应该是 IMO 公认的答案 - 比我分享的更干净,并且适用于任何形状!
    • @Rabbid76 非常感谢您的帮助!
    • @KacperFloriański 是的,这个答案更简洁通用!我已经实现了它并将其标记为已接受的答案!谢谢!
    【解决方案2】:

    我找不到使用 pygame 函数的方法,所以我在这里做了一个关于如何自己做的快速演示:

    import pygame
    import math
    import time
    
    # Screen dimensions
    WIDTH = 600
    HEIGHT = 400
    
    # Circle and screen colours
    WHITE = (255, 255, 255)
    RED = (255, 0, 0)
    GREEN = (0, 255, 0)
    BLUE = (0, 0, 255)
    
    # Circle data
    BIGGER_POS = (300, 150)
    SMALLER_POS = (300, 220)
    BIGGER_RADIUS = 130
    SMALLER_RADIUS = 100
    BIGGER_COLOUR = GREEN
    SMALLER_COLOUR = BLUE
    INTERSECTION_COLOUR = RED
    
    
    def prepare_screen():
        """
        Create the initial screen.
        """
        pygame.init()
        screen = pygame.display.set_mode((WIDTH, HEIGHT))
        screen.fill(WHITE)
        return screen
    
    
    def draw_circles(screen):
        """
        Draw the circles and wait to visually inspect what they look like.
        """
        bigger = pygame.draw.circle(screen, BIGGER_COLOUR, BIGGER_POS, BIGGER_RADIUS)
        smaller = pygame.draw.circle(screen, SMALLER_COLOUR, SMALLER_POS, SMALLER_RADIUS)
        pygame.display.update()
        time.sleep(3)
        return bigger, smaller
    
    
    def calculate_distance(p1: tuple, p2: tuple):
        """
        Calculate distance between two points p1 and p2.
        """
        return math.sqrt(((p1[0] - p2[0])**2) + ((p1[1] - p2[1])**2))
    
    
    def draw_intersection(screen, bigger, smaller):
        """
        Animation to mark intersecting points with red.
        
        Ideally this should only go through colliding points, but I'm lazy and made it iterate through all pixels
        instead.
        """
        for x in range(WIDTH):
            for y in range(HEIGHT):
                print("Checking point", x, y)
                
                # A point is in the intersection if it's within the radius-es of both circles
                if calculate_distance(bigger.center, (x, y)) <= BIGGER_RADIUS and \
                        calculate_distance(smaller.center, (x, y)) <= SMALLER_RADIUS:
                    screen.set_at((x, y), INTERSECTION_COLOUR)
                    pygame.display.update()
    
    
    # Get screen to draw on
    screen = prepare_screen()
    
    # Draw some initial circles
    bigger, smaller = draw_circles(screen)
    
    # Draw the intersection
    draw_intersection(screen, bigger, smaller)
    
    # Finally sleep some to allow visual inspection, and quit
    time.sleep(3)
    pygame.quit()
    

    根据需要随意调整 - 请注意,可以优化各个地方,使其更具可读性等。

    结果:

    如果有什么不清楚的地方请告诉我。

    【讨论】:

    • 谢谢@Kacper。答案很有帮助!
    猜你喜欢
    • 1970-01-01
    • 2021-10-09
    • 2019-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-05
    相关资源
    最近更新 更多