-4

How can I get the exact location of a collision between two sprites?

And if there are multiple pixels overlapping, maybe getting a list of the pixels location. I want to spawn particles at that point and would need it for other functions too.

Pseudo code:

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

My code

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)
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Woww
  • 344
  • 2
  • 10
  • 1
    Please post your code. – Russ J Nov 09 '20 at 23:37
  • 1
    Google your question before posting it here, there are dozens of resources on the first page – NotZack Nov 09 '20 at 23:40
  • Gosh, you guys are friendly. I looked on google, youtube and stackoverflow, and tried to get a hang of the docs, but all I can find is simply collision detection. And why does this question should require posted code? It is probably just one function, which I cannot get right. Like seriously, have you even took a closer look at your google results – Woww Nov 09 '20 at 23:57
  • @RandomDavis ^this – Woww Nov 09 '20 at 23:59
  • @NotZack ^also this – Woww Nov 09 '20 at 23:59
  • Your answer probably is just one function hence a simple Google result as an answer. For an unknown reason that does not work for you, so you should post your code as asked, or explain why your case is different from the normal ones – NotZack Nov 10 '20 at 00:44
  • Your question has many down votes because you have not explained much of anything – NotZack Nov 10 '20 at 00:44
  • @NotZack Zack As I said. Google does not yield results. My case is not different from the normal ones. I never said that. And I posted pseudo code, if you really need that to understand the question. – Woww Nov 10 '20 at 01:26
  • @RussJ And done – Woww Nov 10 '20 at 01:40
  • 1
    @Rabbid76 - If I many present a dissenting opinion - this question is about the intersection area of a collision, and not How-to-collide. I disagree that it's a duplicate. Also I did search for examples of this intersection area, and found nothing appropriate for Python/PyGame. – Kingsley Nov 11 '20 at 01:42
  • @Kingsley I see – Rabbid76 Nov 11 '20 at 05:23

1 Answers1

2

Based on the answer: https://stackoverflow.com/a/57023183/1730895

It's fairly easy to calculate the intersection of the rectangles:

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 )

So use pygame.rect.colliderect() (doco) first to determine if there's actually any overlap. Obviously this gives you an overlapping region, so to answer your question, it could be every pixel within this rectangular area. But perhaps you could just take the centroid for use as a "happening at" point.

example demo

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()

If pixel-perfect collision is desired, use Surface.subsurface() with the overlap rectangle's co-ordinates on the bitmap mask of both sprites. This gives you two bit-masks (maskA and maskB) which you know overlap somehow.

I can't think of a fast way to find the exact pixels of overlap between these two sub-sections. However it's quite easy to iterate through each of the mask-pixels, finding maskA & maskB pairs that are both "on". Obviously you need to convert from screen co-ordinates to sprite co-ordinates during this step, but this is just a subtraction of the sprite's current screen x and y.

What you really want is the "edge" of the bitmap-intersection, but that's another question.

Kingsley
  • 14,398
  • 5
  • 31
  • 53
  • Thank you for your answer. I will wrap my head around it and play with the code :) And also a huge thanks for actually answering my question. I kinda felt like I was not speaking english looking at the comments I got (and the duplicate flag now ^^) – Woww Nov 10 '20 at 07:50
  • @Woww - Thanks for the hug! It's *very* common for people to post questions, and then expect a fully engineered, debugged and commented answer. Once you see a few of these, you get a bit sensitive when questions start to look like a "Gimme teh codez!" demand. That's why people sometimes get a bit snarky about words-only questions. Me, I'm just here for fun. – Kingsley Nov 11 '20 at 01:38