【发布时间】:2023-03-24 19:29:01
【问题描述】:
我正在做一个 pygame 项目,但遇到了问题。我有两个圆圈 A 和 B,如下所示。重叠的现在我只想填充两个圆圈共有的圆圈的一部分。有什么方法可以实现吗?
我知道我可以用红色填充圆 B,用白色填充圆 A,但是有一个特定区域,圆 A 超出了该区域。所以我无法实现。
这张图片中提到了圆圈和填充位置的图像:
【问题讨论】:
我正在做一个 pygame 项目,但遇到了问题。我有两个圆圈 A 和 B,如下所示。重叠的现在我只想填充两个圆圈共有的圆圈的一部分。有什么方法可以实现吗?
我知道我可以用红色填充圆 B,用白色填充圆 A,但是有一个特定区域,圆 A 超出了该区域。所以我无法实现。
这张图片中提到了圆圈和填充位置的图像:
【问题讨论】:
使用每个像素的 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()
【讨论】:
我找不到使用 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()
根据需要随意调整 - 请注意,可以优化各个地方,使其更具可读性等。
结果:
如果有什么不清楚的地方请告诉我。
【讨论】: