I am trying to make bullets bounce of walls, but I can't figure out how to correctly do the collision detection. What I am currently doing is iterating through all the solid blocks and if the bullet hits the bottom, top or sides, its vector is adjusted accordingly. However, sometimes when I shoot, the bullet doesn't bounce, I think it's when I shoot at a border between two blocks.

Here is the update method for my Bullet class:

def update(self, dt):
    if self.can_bounce:
        #if the bullet hasnt bounced find its vector using the mousclick pos and player pos
        speed = -10.
        range = 200
        distance = [self.mouse_x - self.player[0], self.mouse_y - self.player[1]]
        norm = math.sqrt(distance[0] ** 2 + distance[1] ** 2)
        direction = [distance[0] / norm, distance[1 ] / norm]
        bullet_vector = [direction[0] * speed, direction[1] * speed]

        self.dx = bullet_vector[0]
        self.dy = bullet_vector[1]

    #check each block for collision
    for block in self.game.solid_blocks:
        last = self.rect.copy()
        if self.rect.colliderect(block):
            topcheck = self.rect.top < block.rect.bottom and self.rect.top > block.rect.top
            bottomcheck = self.rect.bottom > block.rect.top and self.rect.bottom < block.rect.bottom
            rightcheck = self.rect.right > block.rect.left and self.rect.right < block.rect.right 
            leftcheck = self.rect.left < block.rect.right and self.rect.left > block.rect.left
            each test tests if it hit the top bottom left or right side of the block its colliding with 
            if self.can_bounce:                      
                if topcheck: 
                    self.rect = last
                    self.dy  *= -1 
                    self.can_bounce = False
                    print "top"

                if bottomcheck:
                    self.rect = last
                    self.dy  *= -1 #Bottom check
                    self.can_bounce = False
                    print "bottom"

                if rightcheck:
                    self.rect = last 
                    self.dx  *= -1 #right check
                    self.can_bounce = False
                    print "right"

                if leftcheck:
                    self.rect = last
                    self.dx  *= -1 #left check
                    self.can_bounce = False
                    print "left"

                # if it has already bounced and colliding again kill it

    for enemy in self.game.enemies_list:
        if self.rect.colliderect(enemy):
    #update position
    self.rect.x -= self.dx
    self.rect.y -= self.dy

This definitely isn't the best way to do it but I can't think of another way. If anyone has done this or can help that would be awesome!

  • \$\begingroup\$ Hey man! Anyhow, an idea may be to add blocks (with 100% alpha) between the other blocks, so it always bounces off of something? If your problem is that it is hitting the intersection of the blocks, that should make sure that collision happens. \$\endgroup\$ – Pip Dec 12 '13 at 21:34
  • \$\begingroup\$ its detecting collision between blocks but its the wrong collision, i need a better way to test it \$\endgroup\$ – Serial Dec 13 '13 at 1:57
  • \$\begingroup\$ I see. I don't think there is a better way to do this in Pygame, so maybe you could find an external library? nullege.com/codes/search?cq=collision \$\endgroup\$ – Pip Dec 13 '13 at 3:21
  • \$\begingroup\$ @TheProgramm3r No, I know there is ive seen it done but im having trouble implementing it properly \$\endgroup\$ – Serial Dec 13 '13 at 3:34

If you try and do the X and Y collision at the same time, you will find it troublesome to implement any kind of bouncing; it's more effort to calculate which way the object will need to bounce.

To remedy this, we can split up the X and Y collision calculation, and the velocity reversing calculation. some pseudocode:

move(int x, int y){
    pos.x += x;
    pos.y += y;

the checkXCollision methods simply reverse the velocity and maybe remove some depending on your requirements.

  • \$\begingroup\$ Your answer was short enough to be flagged for a low-quality check. It is rather succinct. If you think it is the correct solution to the OP's problem, you might elaborate about why their attempted method failed. \$\endgroup\$ – Seth Battin Aug 12 '14 at 4:26
  • 4
    \$\begingroup\$ I think you have a valid solution, but please elaborate so that it can be an excellent answer. \$\endgroup\$ – congusbongus Aug 12 '14 at 8:10
  • \$\begingroup\$ That and a little code goes a long way. \$\endgroup\$ – Tom 'Blue' Piddock Aug 12 '14 at 8:18

Pygame has a built in and very good collision detection function for sprites. If you have one sprite, and want to tell if it is colliding with members of another group of sprites, you can do this:

collisions = pygame.sprite.spritecollide(<sprite>,<group>,False)     #argument one is the sprite, argument two is the group to test collisions with the sprite for, and the final argument should almost always be False, because when it is True, colliding sprites will automatically get deleted.
for item in collisions:                                              #Spritecollide returns a list of colliding sprites. This will iterate through them.
    if item != <sprite>:                                             #spritecollide will also always return that the sprite is colliding with itself. this will filter that out, because you don't want this information.
        print "collision detected, insert code to run on collision here or return True from a function"

This should work fine.

  • 3
    \$\begingroup\$ Yes, if you read my code, or my question even then, you would know that im already using colliderect, and my question isnt how to use simple collision it is how to tell if the sprite is touching a floor (horizontal), or a wall(vertical) \$\endgroup\$ – Serial Dec 16 '13 at 0:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.