Multiple sprite collision detections

Viewed 98

Ok, so I have been trying to figure out how to set this up and can't get it working properly. I'm trying to get the functionality similar to the moving logs in the game Frogger if you are familiar with it. So far what I have works with the collision detection for only one pygame.sprite.Group()

import pygame
import os
import random

os.environ['SDL_VIDEO_CENTERED'] = '1'

WIDTH = 480
HEIGHT = 720
FPS = 60

# Moving Object spacing setup first row 
INSTANCE_COUNT = 0
BOX_WIDTH = 30
SPACING = 120

# object speed
pos_objspeed = 1
neg_objspeed = -1

BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)

pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((30, 30))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.bottom = HEIGHT - 96
        self.speedx = 0
        self.speedy = 0

class MovingObj_Test(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((90, 30))
        self.image.fill(RED)
        self.rect = self.image.get_rect()
        self.rect.x = (INSTANCE_COUNT * (SPACING+ BOX_WIDTH))
        #self.rect.x = random.randrange(WIDTH)
        self.rect.bottom = 384
        self.speedx = pos_objspeed

    def update(self):
        self.rect.x += self.speedx
        if self.rect.x >= 480:
            self.rect.x = -30
            self.rect.bottom = 384
            self.speedx = pos_objspeed        

class MovingObj_TestTwo(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((90, 30))
        self.image.fill(RED)
        self.rect = self.image.get_rect()
        self.rect.x = (INSTANCE_COUNT * (SPACING+ BOX_WIDTH))
        #self.rect.x = random.randrange(WIDTH)
        self.rect.bottom = 336
        self.speedx = neg_objspeed

    def update(self):
        self.rect.x += self.speedx
        if self.rect.x >= 480:
            self.rect.x = -30
            self.rect.bottom = 336
            self.speedx = neg_objspeed

all_sprites = pygame.sprite.Group()
movingobj_l = pygame.sprite.Group()
movingobj_r = pygame.sprite.Group()

for i in range (3):
    INSTANCE_COUNT = i + 1
    obj1 = MovingObj_Test()
    all_sprites.add(obj1)
    movingobj_l.add(obj1)

for i in range (3):
    INSTANCE_COUNT = i + 1
    obj2 = MovingObj_TestTwo()
    all_sprites.add(obj2)
    movingobj_r.add(obj2)

player = Player()
all_sprites.add(player)

running = True
onLogLeft = False
onLogRight = False
groundSpd = 48
while running:

    clock.tick(FPS)

    hitsleft = pygame.sprite.spritecollide(player, movingobj_l, False, pygame.sprite.collide_rect)
    for hit in hitsleft:
        player.speedx = pos_objspeed
        player.speedy = 0
        onLogLeft = True
    if len(hitsleft) == 0:
        onLogLeft = False
        player.speedx = 0
        player.speedy = 0
    hitsright = pygame.sprite.spritecollide(player, movingobj_r, False, pygame.sprite.collide_rect)
    for hit in hitsright:
        player.speedx = neg_objspeed
        player.speedy = 0
        onLogRight = True
    if len(hitsright) == 0:
        onLogRight = False
        player.speedx = 0
        player.speedy = 0


    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                player.speedx = -groundSpd
            if event.key == pygame.K_RIGHT:
                player.speedx = groundSpd
            if event.key == pygame.K_UP:
                player.speedy = -groundSpd
            if event.key == pygame.K_DOWN:
                player.speedy = groundSpd

        if event.type == pygame.KEYUP and onLogLeft == False and onLogRight == False:
            if event.key == pygame.K_LEFT:
                player.speedx = 0
            if event.key == pygame.K_RIGHT:
                player.speedx = 0
            if event.key == pygame.K_UP:
                player.speedy = 0
            if event.key == pygame.K_DOWN:
                player.speedy = 0

    if onLogLeft == False and onLogRight == False and player.rect.bottom <= 384:
        running = False

    player.rect.x += player.speedx
    player.rect.y += player.speedy

    if event.type == pygame.QUIT:
        running = False



    #player.rect.x += player.speedx
    #player.rect.y += player.speedy

    all_sprites.update()
    screen.fill(BLACK)
    all_sprites.draw(screen)
    pygame.display.flip()



pygame.quit()
quit()

Ok so in my code the

hitsright = pygame.sprite.spritecollide(player, movingobj_r, False, pygame.sprite.collide_rect)

checks the collision and updates the players speed how I'm expecting it to but, the

hitsleft = pygame.sprite.spritecollide(player, movingobj_l, False, pygame.sprite.collide_rect)

is not doing the same.

I'm confused as to why this is if anyone has any ideas. Also how could I fix it to work for both?

1 Answers

The code for left and right behaves different, because if a collision with hitsleft is detected, the player.speedx is set:

for hit in hitsleft:
   player.speedx = pos_objspeed

But if there is a collision with hitsleft there it no collision with hitsright and player.speedx is reset immediately:

if len(hitsright) == 0:
   onLogRight = False
   player.speedx = 0

You have to set player.speedx dependent on both conditions (e.g. in a if - elif - else statement):

while running:
    # [...]

    hitsleft = pygame.sprite.spritecollide(player, movingobj_l, False, pygame.sprite.collide_rect)
    onLogLeft = any(hitsleft)

    hitsright = pygame.sprite.spritecollide(player, movingobj_r, False, pygame.sprite.collide_rect)
    onLogRight = any(hitsright)

    player.speedy = 0
    if onLogLeft:
        player.speedx = pos_objspeed
    elif onLogRight:
        player.speedx = neg_objspeed
    else:
        player.speedx = 0
Related