0

I am trying to work out how to detect and resolve collisions between moving sprites in pygame, I followed the logic of this video: https://www.youtube.com/watch?v=VpSWuywFlC8

The basic idea is that I track the current rectangle position as well as the previous rectangle position for each sprite and use that to detect where collisions have come from.

For example, to check if the player has collided at the bottom I use: player.rect.bottom >= sprite.rect.top and player.old_rect.bottom < sprite.old_rect.top that way I know that the player's bottom is in the other sprite and that it was above it in the previous frame.

The problem I have is that the collision detection only works sporadically and thus also breaks the collision resolution. Although, if I only look at a collision on a single side it does work. I am just not sure what the problem is with the collision detection.

Code so far:

import pygame, sys

class StaticObstacle(pygame.sprite.Sprite):
    def __init__(self,pos,size,groups):
        super().__init__(groups)
        self.image = pygame.Surface(size)
        self.image.fill('yellow')
        self.rect = self.image.get_rect(topleft = pos)
        self.old_rect = self.rect

class MovingVerticalObstacle(StaticObstacle):
    def __init__(self,pos,size,groups):
        super().__init__(pos, size, groups)
        self.image.fill('green')
        self.direction = pygame.math.Vector2((0,1))
        self.speed = 8

    def update(self):
        self.old_rect = self.rect.copy()
        
        if self.rect.bottom >= 600 or self.rect.top <= 120:
            self.direction.y *= -1

        self.rect.y += self.direction.y * self.speed

class MovingHorizontalObstacle(StaticObstacle):
    def __init__(self,pos,size,groups):
        super().__init__(pos, size, groups)
        self.image.fill('purple')
        self.direction = pygame.math.Vector2((1,0))
        self.speed = 6

    def update(self):
        self.old_rect = self.rect.copy()
        if self.rect.right >= 1000 or self.rect.left <= 600:
            self.direction.x *= -1
 
        self.rect.x += self.direction.x * self.speed 

class Player(pygame.sprite.Sprite):
    def __init__(self,groups,obstacles):
        super().__init__(groups)
        
        # image
        self.image = pygame.Surface((30,60))
        self.image.fill('blue')
        
        # position
        self.rect = self.image.get_rect(topleft = (640,360))
        self.old_rect = self.rect.copy()
        
        # movement
        self.direction = pygame.math.Vector2()
        self.speed = 5
        self.obstacles = obstacles

    def input(self):
        keys = pygame.key.get_pressed()

        # movement input
        if keys[pygame.K_UP]: 
            self.direction.y = -1
        elif keys[pygame.K_DOWN]: 
            self.direction.y = 1
        else: 
            self.direction.y = 0

        if keys[pygame.K_RIGHT]: 
            self.direction.x = 1
        elif keys[pygame.K_LEFT]: 
            self.direction.x = -1
        else: 
            self.direction.x = 0

    def collisions(self):
        collision_sprites = pygame.sprite.spritecollide(self,self.obstacles,False)
        if collision_sprites:
            for sprite in collision_sprites:
                if self.rect.top <= sprite.rect.bottom and self.old_rect.top > sprite.old_rect.bottom:
                    print('top collision')
                    self.rect.top = sprite.rect.bottom
                elif self.rect.bottom >= sprite.rect.top and self.old_rect.bottom < sprite.old_rect.top:
                    print('bottom collision')
                    self.rect.bottom = sprite.rect.top
                elif self.rect.right >= sprite.rect.left and self.old_rect.right < sprite.old_rect.left:
                    print('right collision')
                    self.rect.right = sprite.rect.left
                elif self.rect.left >= sprite.rect.right and self.old_rect.left < sprite.old_rect.right:
                    print('left collision')
                    self.rect.left = sprite.rect.right

    def update(self):
        self.old_rect = self.rect.copy()
        self.input()
        
        self.rect.topleft += self.direction * self.speed 
        self.collisions()

# general setup
pygame.init()
screen = pygame.display.set_mode((1280,720))
clock = pygame.time.Clock()

# group setup
all_sprites = pygame.sprite.Group()
collision_sprites = pygame.sprite.Group()

# sprite setup
StaticObstacle((100,300),(100,50),[all_sprites,collision_sprites])
StaticObstacle((800,600),(100,200),[all_sprites,collision_sprites])
StaticObstacle((900,200),(200,10),[all_sprites,collision_sprites])
MovingVerticalObstacle((200,300),(200,60),[all_sprites,collision_sprites])
MovingHorizontalObstacle((850,350),(100,100),[all_sprites,collision_sprites])
Player(all_sprites,collision_sprites)

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

    screen.fill('black')
    all_sprites.update()
    all_sprites.draw(screen)

    pygame.display.update()
    clock.tick(60)
Another_coder
  • 728
  • 1
  • 9
  • 23

0 Answers0