happybanana78
happybanana78

Reputation: 1

Pygame strange collision detection

I want to try making a platform game with pygame.

For some reason, if I check only x or y collisions, everything works fine, but as soon as I check them both every time my player hits the ground or the ceiling, it just teleports on the side of the block. I tried a few print statements to verify if a collision happened at all, and it didn't if both collision checks are active as soon the player hits the ground without checking for collision it teleports on the side.

This is my code, collisions are handled with the collision_x() and collision_y() methods:

       # Get player input
    def get_player_input(self):
        global do_move, player_speed_y, player_speed_x
        do_move = True
        key = pygame.key.get_pressed()
        if key[pygame.K_d] and do_move:
            self.player.move_ip(player_speed_x, 0)
            self.pos_0_x = self.player.x + player_speed_x
        elif key[pygame.K_a] and do_move:
            self.player.move_ip(-player_speed_x, 0)
            self.pos_0_x = self.player.x - player_speed_x

        elif key[pygame.K_s] and do_move:
            self.player.move_ip(0, player_speed_y)
            self.pos_0_y = self.player.y + player_speed_y
        elif key[pygame.K_w] and do_move:
            self.player.move_ip(0, -player_speed_y)
            self.pos_0_y = self.player.y - player_speed_y

    # Get collisions with the player on x
    def collisions_x(self):
        global do_move, player_speed_x
        self.map_gen()
        for sprite in self.tiles.sprites():
            if sprite.rect.colliderect(self.player):
                if self.player.x > self.pos_0_x:    # Check if player is colliding on his left side
                    do_move = False
                    self.player.x = self.player.x + 1
                    self.player.y = self.pos_0_y

                if self.player.x < self.pos_0_x:  # Check if player is colliding on his right side
                    do_move = False
                    self.player.x = self.player.x - 1
                    self.player.y = self.pos_0_y

    # Get collisions with the player on y
    def collisions_y(self):
        global do_move, player_speed_y
        self.map_gen()
        for sprite in self.tiles.sprites():
            if sprite.rect.colliderect(self.player):
                if self.player.y < self.pos_0_y:  # Check if player is colliding on his bottom side
                    do_move = False
                    player_speed_y = 0
                    self.player.y = self.player.y - 1

                if self.player.y > self.pos_0_y:  # Check if player is colliding on his top side
                    do_move = False
                    self.player.y = self.player.y + 1

    # Put the player on the screen
    def update_player(self, surface):
        self.get_player_input()
        self.collisions_x()
        self.collisions_y()
        pygame.draw.rect(WIN, (200, 0, 0), self.player)

Upvotes: 0

Views: 81

Answers (1)

happybanana78
happybanana78

Reputation: 1

At the end I partially managed to solve the issue. Now, collisions happen without problems. The only thing that I can't get to work right now is the fact that when the player hits the ground, for some unknown reason it can't go left anymore.

Here is the updated code:

This is the gravity function

def apply_gravity(self):
    self.player.y += player_speed_y + 0.5 * gravity

The collisions_x() function handles x collisions

   def collisions_x(self):
    global player_speed_x
    self.map_gen()
    for sprite in self.tiles.sprites():
        if self.player.colliderect(sprite):
            if self.player.right > sprite.rect.right:  # Check if player is colliding on his left side
                self.player.left = sprite.rect.right
            if self.player.left < sprite.rect.left:  # Check if player is colliding on his right side
                self.player.right = sprite.rect.left

The collisions_y() function handles y collisions (at the moment only downwards)

def collisions_y(self):
    global player_speed_y
    for sprite in self.tiles.sprites():
        if self.player.colliderect(sprite):
            if player_speed_y > 0:
                self.player.bottom = sprite.rect.top

And this function is then called in the loop to draw all on the screen

   def update_player(self, surface):
    self.get_player_input()
    self.apply_gravity()
    self.collisions_x()
    self.collisions_y()
    pygame.draw.rect(surface, (200, 0, 0), self.player)

Here is a short video the indicates what my problem looks like:

https://www.youtube.com/watch?v=IVRG0Th75YI

Upvotes: 0

Related Questions