python-3.x 遮罩多边形和子画面之间的碰撞

disbfnqx  于 2023-06-07  发布在  Python
关注(0)|答案(2)|浏览(265)

这是我第一次尝试使用遮罩碰撞,但找不到这种特定情况(多边形和精灵遮罩碰撞)的参考。
我希望精灵的能力,以检测其他精灵使用'视野'的方法。下面是我的Pygame应用程序的一个例子:

一堆蠕虫,显示其FOV以进行调试。在这种情况下,我希望他们看到小绿色。首先,我可以将FOV生成为多边形。我在pygame.display Surface(简称program.screen)上绘制它。然后,我检查精灵组中的每个‘目标‘,并检查多边形和目标之间的矩形碰撞-工作正常。所以所有的数学和计算都是正确的,但我不能得到下一位与面具面具碰撞工作。在我所附的代码中,print(“Detection”)语句永远不会被调用。

#Check if entity can detect its target given its fov
#
#@param entity: pygame.sprite.Sprite object performing the look() function
#@param fov: The angle and depth of view of 'entity', in the form of [angle (degrees), depth (pixels)]
#@param target: pygame.sprite.Sprite object the 'entity' is looking out for
#@param program: the main instance that runs and handles the entire application

def look(entity, fov, target, program):
    r = fov[1] * np.cos(np.pi / 180 * fov[0])
    coords_1 = (r * np.sin(entity.rot * np.pi / 180) + entity.x, r * np.cos(entity.rot * np.pi / 180) + entity.y)
    coords_2 = (r * np.sin((entity.rot + 2*fov[0]) * np.pi / 180) + entity.x, r * np.cos((entity.rot + 2*fov[0]) * np.pi / 180) + entity.y)
    poly_coords = ((entity.x, entity.y), coords_1, coords_2)  # The coordinates of the fov

    view = pygame.draw.polygon(program.screen, WHITE, poly_coords)  # Draw the fov white for indication
    pygame.display.update(view)
    # Iterate over all sprites
    for i in program.all_sprites:
        if isinstance(i, target):
            # Rough check for if this item is colliding with the fov polygon
            if view.colliderect(i.rect):
                # Exact check if this item is roughly colliding with the fov polygon
                mask = pygame.mask.from_surface(i.image)
                if pygame.mask.from_surface(program.screen).overlap(mask, (0, 0)):
                    # For now, colour the polygon red as indication
                    signal = pygame.draw.polygon(program.screen, RED, [(entity.x, entity.y), coords_1, coords_2])
                    print("Detection")
                    pygame.display.update(signal)

当我使用

if pygame.sprite.collide_mask(mask, pygame.mask.from_surface(program.screen)):

检查面具时我会得到一个

AttributeError: 'pygame.mask.Mask' object has no attribute 'rect'

我还尝试在不同的表面上绘制多边形,结果与第一个代码相同(未检测到):

def look(entity, fov, target, program):
    r = fov[1] * np.cos(np.pi / 180 * fov[0])
    coords_1 = (r * np.sin(entity.rot * np.pi / 180) + entity.x, r * np.cos(entity.rot * np.pi / 180) + entity.y)
    coords_2 = (r * np.sin((entity.rot + 2*fov[0]) * np.pi / 180) + entity.x, r * np.cos((entity.rot + 2*fov[0]) * np.pi / 180) + entity.y)
    poly_coords = ((entity.x, entity.y), coords_1, coords_2)  # The coordinates of the fov

    view_layer = pygame.Surface((500, 500))  # some random size big enough to hold the fov
    #view_layer.fill(BLUE)
    view = pygame.draw.polygon(view_layer, WHITE, poly_coords)  # Draw the fov white for indication
    pygame.display.update(view)
    program.screen.blit(view_layer, (min(poly_coords[0]), max(poly_coords[1])))
    pygame.display.update(view)
    # Iterate over all sprites
    for i in program.all_sprites:
        if isinstance(i, target):
            # Rough check for if this item is colliding with the fov polygon
            if view.colliderect(i.rect):
                # Exact check if this item is roughly colliding with the fov polygon
                mask = pygame.mask.from_surface(i.image)
                if pygame.mask.from_surface(view_layer).overlap(mask, (0, 0)):
                    # For now, colour the polygon red as indication
                    signal = pygame.draw.polygon(program.screen, RED, [(entity.x, entity.y), coords_1, coords_2])
                    print("Detection")
                    pygame.display.update(signal)

我尝试的方法有什么问题,或者有更好的方法吗?
谢谢,克雷斯

fumotvh3

fumotvh31#

pygame.sprite.collide_mask()用于pygame.sprite.Sprite对象。pygame.sprite.collide_mask()的参数是sprites而不是masks。sprite对象需要具有属性.rect.mask。需要rect属性来计算屏幕上对象之间的位置偏移,mask是包含位掩码的pygame.mask.Mask对象。
例如

if pygame.sprite.collide_mask(sprite1, sprite2):
    print("hit")

另请参阅如何制作碰撞遮罩?
如果您不使用pygame.sprite.Sprite,则必须使用pygame.mask.Mask.overlap
例如,如果你有两个pygame.mask.Mask对象(mask1mask2),分别位于(x1y1)和(x2y2):

offset = (x2 - x1), (y2 - y1)
if mask1.overlap(mask2, offset):
    print("hit")

另请参阅PyGame中的遮罩之间的碰撞和PyGame与遮罩的碰撞不起作用。

w8f9ii69

w8f9ii692#

感谢你的评分还有其他问题,以及与我的代码,这就是为什么我认为张贴这作为答案。
我做了一个单独的表面来画多边形。更多的数学涉及到定义多边形内接的矩形,并将原始(显示)多边形坐标转换到新的表面上。曲面的大小应与计算的边界矩形相同。
至于面具计算本身,基本上就是Rabbid76的答案。

def look(entity, fov, target, program):
    r = fov[1] * np.cos(np.pi / 180 * fov[0])
    coords_1 = (r * np.sin(entity.rot * np.pi / 180) + entity.x, r * np.cos(entity.rot * np.pi / 180) + entity.y)
    coords_2 = (r * np.sin((entity.rot + 2*fov[0]) * np.pi / 180) + entity.x, r * np.cos((entity.rot + 2*fov[0]) * np.pi / 180) + entity.y)
    poly_coords = ((entity.x, entity.y), coords_1, coords_2)  # The coordinates of the fov
    poly_rect = hf.poly_get_box(poly_coords)

    view_layer = pygame.Surface((poly_rect.width, poly_rect.height), pygame.SRCALPHA)
    #view_layer.fill(DODGER_BLUE)  # for debugging only
    view_layer.convert_alpha()

    new_poly_coords = hf.poly_coords_in_surface(poly_coords, (poly_rect.x, poly_rect.y))
    pygame.draw.polygon(view_layer, WHITE, new_poly_coords, 0)  # Draw the fov white for indication
    program.screen.blit(view_layer, (poly_rect.x, poly_rect.y))  # blits/updates/flips for debugging only
    pygame.display.update(poly_rect)
    pygame.display.flip()
    # Iterate over all sprites
    for i in program.all_sprites:
        if isinstance(i, target):
            # Rough check for if this item is colliding with the fov polygon
            if poly_rect.colliderect(i.rect):
                # Exact check if this item is roughly colliding with the fov polygon
                view_mask = pygame.mask.from_surface(view_layer)
                mask = pygame.mask.from_surface(i.image)
                pygame.display.flip()
                if view_mask.overlap(mask, (int(i.x) - poly_rect.x, int(i.y) - poly_rect.y)):
                    # For now, colour the polygon red as indication
                    signal = pygame.draw.polygon(program.screen, RED, [(entity.x, entity.y), coords_1, coords_2])
                    print("Detection")
                    pygame.display.update(signal)

辅助函数:

# Defines a width and height for a 3-point polygon
def poly_get_box(coords):
    xs = []; ys = []
    for i in coords:
        xs.append(i[0])
        ys.append(i[1])

    width = np.ceil(max(xs) - min(xs))
    height = np.ceil(max(ys) - min(ys))
    box = pygame.Rect(np.ceil(min(xs)), np.ceil(min(ys)), width, height)

    return box

# Translates polygon coordinates from display coordinates to view-layer coordinates
def poly_coords_in_surface(polyCoords, surfCoords):
    new_coords = []
    for i in polyCoords:
        x = i[0] - surfCoords[0]
        y = i[1] - surfCoords[1]
        new_coords.append((x, y))

    return new_coords

相关问题