Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pygame stop movement on collision detection

I'm essentially trying to make a "solid" object with pygame. The goal is to repel the player when they come in contact. What I'm currently using (but doesn't work correctly) is the following:

keys_pressed = pygame.key.get_pressed()
if 1 in keys_pressed:
    if keys_pressed[K_w]:
        self.player_l[1] += -2
        if self.player_r.colliderect(self.tower_r): self.player_l[1] -= -2
    if keys_pressed[K_a]:
        self.player_l[0] += -2
        if self.player_r.colliderect(self.tower_r): self.player_l[0] -= -2
    if keys_pressed[K_s]:
        self.player_l[1] += 2
        if self.player_r.colliderect(self.tower_r): self.player_l[1] -= 2
    if keys_pressed[K_d]:
        self.player_l[0] += 2
        if self.player_r.colliderect(self.tower_r): self.player_l[0] -= 2

The problem with this is that the player gets "stuck" inside the tower Rect, despite returning to a location where they were before the collision is initiated, the player Rect will always be pulled back in to the tower, and the collision will continue to trigger. After initially touching the tower Rect, the player will be unable to move in any direction.

like image 859
Dan Doe Avatar asked Oct 21 '22 11:10

Dan Doe


1 Answers

I have done the same thing in a pygame game of mine. What you want to do is make a function for moving that all objects will use. It makes it impossible to go through any sprite in a render updates group called everything. If a sprite is not part of everything, it will not collide. Here is the function. This creates a resistance of a certain amount for collisions. Basically, upon pushing on an object, it will push a certain amount back. Any object that doesn't call the move function will not move even if it is pushed upon, so only objects that can move in the first place can be pushed, while things like walls will not slide across the board when you push them.

    def moveRelative(self,other,speed):                                   #This function is a function the one you need uses, which you may find useful. It is designed to move towards or a way from another sprite. Other is the other sprite, speed is an integer, where a negative value specifies moving away from the sprite, which is how many pixels it will move away from the target. This returns coordinates for the move_ip function to move to or away from the sprite, as a tuple
            dx = other.rect.x - self.rect.x
            dy = other.rect.y - self.rect.y
            if abs(dx) > abs(dy):
                    # other is farther away in x than in y
                    if dx > 0:
                            return (+speed,0)
                    else:
                            return (-speed,0)
            else:
                    if dy > 0:
                            return (0,+speed)
                    else:
                            return (0,-speed)

    def move(self,dx,dy):
            screen.fill((COLOR),self.rect)                                 #covers over the sprite's rectangle with the background color, a constant in the program
            collisions = pygame.sprite.spritecollide(self, everything, False)
            for other in collisions:
                    if other != self:
                            (awayDx,awayDy) = self.moveRelative(other,-1)  #moves away from the object it is colliding with
                            dx = dx + 9*(awayDx)                           #the number 9 here represents the object's resistance. When you push on an object, it will push with a force of nine back. If you make it too low, players can walk right through other objects. If you make it too high, players will bounce back from other objects violently upon contact. In this, if a player moves in a direction faster than a speed of nine, they will push through the other object (or simply push the other object back if they are also in motion)
                            dy = dy + 9*(awayDy)
            self.rect.move_ip(dx,dy)                                       #this finally implements the movement, with the new calculations being used

it is kind of a lot of code an you may want to change it for your purposes, but this is a pretty good way to do it. If you want to eliminate the bounce back feature, you could consider just setting any movement towards the object to zero, and allowing movement away from it only. I have found the bounce back feature useful and more accurate for my game, however.

like image 89
trevorKirkby Avatar answered Nov 03 '22 05:11

trevorKirkby