Another_coder
Another_coder

Reputation: 810

collision between moving sprites in pygame

I have two moving sprites, one is called wall and it just moves up and down; the other is called Player and it bounces around the screen and changes direction whenever it hit an obstacles.

I got this to work to a degree: The player ball does bounce around but sometimes there is a bug where the ball seems to be confused about the movement and just wobbles back and forth when colliding with the wall. The faster I set the speed of the player ball or the movement of the wall, the more frequent the bug becomes.

Here is the code for the project:

import pygame, sys

# The class that creates the player ball; it does not take user input but just bounces around
class Player(pygame.sprite.Sprite):
    def __init__(self, color, width, height,speed_x,speed_y):
        super().__init__()
        self.image = pygame.Surface([width, height])
        self.image.fill(color)
        self.rect = self.image.get_rect()
        self.speed_x = speed_x
        self.speed_y = speed_y

    def update(self,collision_group):
        self.rect.x += self.speed_x
        self.rect.y += self.speed_y

        # code to get a bounce when the ball hits the edge of the screen
        if self.rect.right >= screen_width or self.rect.left <= 0:
            self.speed_x *= -1
        if self.rect.bottom >= screen_height or self.rect.top <= 0:
            self.speed_y *= -1

        # Code to get a bounce when the player collides with the wall
        collide_object = pygame.sprite.spritecollide(self,collision_group,False)
        if collide_object:
            if collide_object[0].rect.collidepoint(self.rect.midbottom) or collide_object[0].rect.collidepoint(self.rect.midtop):
                self.speed_y *= -1
        if collide_object[0].rect.collidepoint(self.rect.midright) or collide_object[0].rect.collidepoint(self.rect.midleft):
                self.speed_x *= -1          

# Code for the wall, it just moves up and down
class Wall(pygame.sprite.Sprite):
    def __init__(self,width,height,pos_x,pos_y,color):
        super().__init__()
        self.image = pygame.Surface([width,height])
        self.image.fill(color)
        self.rect = self.image.get_rect()
        self.rect.x = pos_x
        self.rect.y = pos_y
        self.speed = 5

    def update(self):
        self.rect.y += self.speed

        if self.rect.bottom >= screen_height:
            self.speed *= -1 
        if self.rect.top <= 0:
            self.speed *= -1

# General setup
pygame.init()
clock = pygame.time.Clock()

# Game Screen
screen_width = 800
screen_height = 800
screen = pygame.display.set_mode((screen_width,screen_height))
pygame.display.set_caption("Side by side collision")

# Creating the sprites and groups
moving_sprites = pygame.sprite.Group()
player = Player((255,0,0),20,20,8,8)
moving_sprites.add(player)

wall_sprites = pygame.sprite.Group()
center_wall = Wall(500,200,300,300,(255,255,0))
wall_sprites.add(center_wall)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    # Drawing
    screen.fill((0,0,0))
    wall_sprites.draw(screen)
    wall_sprites.update()
    moving_sprites.draw(screen)
    moving_sprites.update(wall_sprites)

    pygame.display.flip()
    clock.tick(60)

many thanks in advance :)

Upvotes: 2

Views: 1280

Answers (1)

sahinakkaya
sahinakkaya

Reputation: 6056

You can realize that your code works perfectly if the the wall is moving away from the player when they collide. The problem occurs when they are moving towards each other. This is because your player is actually goes inside the wall, you detect a collision, reverse the speed of the player and at the next iteration your player is still inside the wall (because wall is moving towards your player, the player couldn't find enough time to escape it) and you detect a collision again, reverse the speed of the player...

You can modify your code like this to solve the problem:

if collide_object:
    rect = collide_object[0].rect
    if rect.collidepoint(self.rect.midbottom): # if we hit from bottom
        if self.speed_y > 0: # and the player was moving down
            self.speed_y *= -1 # go up
    elif rect.collidepoint(self.rect.midtop): # if we hit from top
        if self.speed_y < 0: # and the player was moving up
            self.speed_y *= -1 # go down

Upvotes: 2

Related Questions