首页 > 解决方案 > Pygame - 返回碰撞位置

问题描述

如何获得两个精灵之间碰撞的确切位置?

如果有多个像素重叠,可能会得到一个像素位置列表。我想在那个时候产生粒子,并且其他功能也需要它。

伪代码:

obj1.rect..x += obj1.velocity
collision = collide(obj1, obj2):
if collision:
    ?
    return collision_location

我的代码

def _bullet_collision(self):
        for bullet in self.bullets:
            hits = pygame.sprite.spritecollide(bullet, self.aliens, False, pygame.sprite.collide_mask)
            if hits:
                hit_str = 11
                for alien in hits:
                    x, y = alien.x, alien.y
                    spawn_pos = (x, y)
                    self._hit_enemy(alien, x, y, hit_str)
                bullet.bullet_hit(spawn_pos, hit_str)

标签: pythonpygame

解决方案


基于答案:https ://stackoverflow.com/a/57023183/1730895

计算矩形的交点相当容易:

def rectIntersection( rect1, rect2 ):
    """ Given two pygame.Rect intersecting rectangles, return the overlap rect """
    left  = max( rect1.left,  rect2.left )
    width = min( rect1.right, rect2.right ) - left
    top   = max( rect1.top,   rect2.top )
    height= min( rect1.bottom, rect2.bottom ) - top
    return pygame.Rect( left, top, width, height )

所以首先使用pygame.rect.colliderect()( doco ) 来确定是否真的有任何重叠。显然,这为您提供了一个重叠区域,因此要回答您的问题,它可能是该矩形区域内的每个像素。但也许您可以将质心用作“发生在”点。

示例演示

import pygame

# Window size
WINDOW_WIDTH    = 400
WINDOW_HEIGHT   = 400
WINDOW_SURFACE  = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
WINDOW_MAXFPS   = 60

# Colours
DARK_BLUE = (  3,   5,  54)
RED       = (255,   0,   0)
YELLOW    = (200, 200,  20)
GREEN     = ( 20, 200,  20)


def rectIntersection( rect1, rect2 ):
    """ Given two pygame.Rect intersecting rectangles, calculate the rectangle of intersection """
    left  = max( rect1.left,  rect2.left )
    width = min( rect1.right, rect2.right ) - left
    top   = max( rect1.top,   rect2.top )
    height= min( rect1.bottom, rect2.bottom ) - top

    return pygame.Rect( left, top, width, height )


### Initialisation
pygame.init()
pygame.mixer.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )
pygame.display.set_caption("Rect-Rect Intersection")

central_rect = pygame.Rect( 175, 175, 50, 50 )
player_rect  = pygame.Rect(   0,   0, 30, 30 )

### Main Loop
clock = pygame.time.Clock()
done = False
while not done:

    # Handle user-input
    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            done = True
        elif ( event.type == pygame.MOUSEMOTION ):  # move the player's rectangle with the mouse
            mouse_pos = pygame.mouse.get_pos()
            player_rect.center = mouse_pos      

    # Update the window
    window.fill( DARK_BLUE )
    pygame.draw.rect( window, RED,    central_rect, 1 )     # centre rect
    pygame.draw.rect( window, YELLOW, player_rect,  1 )     # player's mouse rect

    # IFF the rectangles overlap, paint the overlap
    if ( player_rect.colliderect( central_rect ) ):
        overlap_rect = rectIntersection( player_rect, central_rect )
        pygame.draw.rect( window, GREEN, overlap_rect )

    pygame.display.flip()

    # Clamp FPS
    clock.tick_busy_loop( WINDOW_MAXFPS )

pygame.quit()

如果需要像素完美的碰撞,Surface.subsurface()请在两个精灵的位图掩码上使用重叠矩形的坐标。这为您提供了两个位掩码(掩码 A 和掩码 B),您知道它们以某种方式重叠。

我想不出一种快速的方法来找到这两个子部分之间重叠的确切像素。但是,很容易遍历每个掩码像素,找到都“打开”的掩码 A 和掩码 B 对。很明显,这一步需要将屏幕坐标转换为精灵坐标,但这只是精灵当前屏幕的减法xy.

您真正想要的是位图交点的“边缘”,但这是另一个问题。


推荐阅读