3
votes

I'm still pretty new to pygame, and coding in general. I'm making a game that requires collision detection, and I seem to be having a problem with it. Every time I run my program, it detects non-existent collisions. Here are some snippets from my code:

class Player(pygame.sprite.Sprite):
    def __init__(self,x,y,width,height):
    pygame.sprite.Sprite.__init__(self)
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.right = False
        self.left = False
        self.up = False
        self.down = False
        self.surf = pygame.Surface((50,50))
        self.rect = self.surf.get_rect()

    def draw(self):
        pygame.draw.rect(screen, (0,0,0), (self.x, self.y, self.width, self.height))

    def collision_test(self):
        if pygame.sprite.collide_rect(self, block1):
            print("a collision is detected")

The above is my player class.

class Block1(pygame.sprite.Sprite):
    def __init__(self,x,y,width,height):
        pygame.sprite.Sprite.__init__(self)
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.surf = pygame.Surface((self.width,self.height))
        self.rect = self.surf.get_rect()

    def draw(self):
        pygame.draw.rect(screen, (150,150,150), (self.x, self.y, self.width, self.height))

And that's my class for the obstacle that my player is supposed to collide with. I'm running a print command in the collision detection for debugging. Like I said, it just constantly prints the message I gave it, even when they aren't colliding. There are no error messages though. Any help would be appreciated! Thanks in advance :)

EDIT:

I changed the collision_test method and added the block1 argument. Now it is this:

    def collision_test(self, block1):
        if pygame.sprite.collide_rect(self, block1):
            print("a collision is detected")

My player and block1 sprites are initiated just before the mainloop, and look like this:

player = Player(50,50,50,50)
block1 = Block1(200, 200, 100, 100)

I am calling the function, collision_test, at the end of the mainloop. In case you need it, here is my full code: https://pastebin.com/LTQdLMuV

1
Hello! Your collision_test(self) method does not take any block1 argument. Where that block1 comes from? Where in the code do you call this function? Please add the portion of code where you instatiate objects from your classes and use them too. - Valentino
Thanks for the quick reply! Just edited my post. Like I said, I'm new to coding and therefore new to stackoverflow, so I'm not sure if you get notified when I edit. - Nolan Dailey
Thanks for the update, I think I found the problem. I'll write it in an answer - Valentino

1 Answers

4
votes

What happens is that you forgot to update the position of the rectangles of your objects.

From pygame docs:

get_rect()
get the rectangular area of the Surface
get_rect(**kwargs)-> Rect
Returns a new rectangle covering the entire surface. This rectangle will always start at 0, 0 with a width. and height the same size as the image.

In both classes Player and Block1 you have a line:

self.rect = self.surf.get_rect()

To use colliderect() the rect attribute must be updated to the position (in pixels) of the image on the screen, otherwise there is a mismatch between the coordinates used by your draw() method and the rectangle used to check the collisions. Do instead:

self.rect = self.surf.get_rect().move(x, y)

so that, when the object is created, the rect attribute corresponds to the real position of the object on the screen.

Remember to update the position of player.rect when you move the player square. Edit your move_player() function too, for example by adding:

player.rect.x = player.x
player.rect.y = player.y

So that rect corresponds on what you have on the screen.

EDIT after comments

If your goal is how to preveent orverlapping between surfaces, it's more complicated. Detecting the collision is only part of the process. The full steps are:

  • move the player object.
  • detecting not only if there is a collision, but also the sides which collided.
  • once the side is detected, move back the player object on that axis.
  • redraw.