1

I have a small problem with my code. The goal is to simulate traffic (two lanes merging into one). I am close to finishing but i have the problem that when a car hits a car of the same Group the whole lane just jams up. I need to somehow be able to make the first car in the collision keep going but not the second (should wait for a small period of time or with a lower speed). I thought about making the collision detection on the right side of the sprite so it stops but the one in front keeps going but i cant get it to work.

import pygame
import random


from pygame.locals import (QUIT, KEYDOWN, K_ESCAPE)

# Define constants for the screen width and height
SCREEN_WIDTH = 1500
SCREEN_HEIGHT = 400
grey=[90 , 90 , 90]
green =[125, 255, 50]
spawnrate_up=700
spawnrate_down=800
dimentions=[75,35]



#CLASSES

#create car
class Car_up (pygame.sprite.Sprite):
    def __init__(self, green, dimentions):
        # Call the parent class (Sprite) constructor
        pygame.sprite.Sprite.__init__(self)

        # Create an image of the block, and fill it with a color.
        # This could also be an image loaded from the disk.
        self.image = pygame.Surface(dimentions)
        self.image.fill(green)

        # Fetch the rectangle object that has the dimensions of the image
        # Update the position of this object by setting the values of rect.x and rect.y
        self.rect = self.image.get_rect()
        self.rect.x = random.randint(-100, -20)
        self.rect.y = 150

        self.speedx= 10
        self.speedy= 0
    # move car and delete once out of screen
    def update(self):
        merge=random.randint(500,1000)
        if self.rect.left > SCREEN_WIDTH:
            self.kill()
        intracollide=pygame.sprite.spritecollide(self, car_up, False)
        if pygame.sprite.spritecollide(self, car_down, False) or len(intracollide)>1:
            self.speedx=self.speedy=0
        elif self.rect.centery<=263 and self.rect.centerx>merge:
            self.speedx=10
            self.speedy=3
        else:
            self.speedx=10
            self.speedy=0
        self.rect.move_ip(self.speedx, self.speedy)


class Car_down(pygame.sprite.Sprite):
    def __init__(self, green, dimentions):
        # Call the parent class (Sprite) constructor
        pygame.sprite.Sprite.__init__(self)

        # Create an image of the block, and fill it with a color.
        # This could also be an image loaded from the disk.
        self.image = pygame.Surface(dimentions)
        self.image.fill(green)


        # Fetch the rectangle object that has the dimensions of the image
        # Update the position of this object by setting the values of rect.x and rect.y
        self.rect = self.image.get_rect()
        self.rect.x = random.randint(-100,-20)
        self.rect.y = 250

        self.speedx= 10
        self.speedy= 0
    # move car and delete once out of screen
    def update(self):


        self.speedx=10
        self.speedy=0
        self.rect.move_ip(self.speedx, self.speedy)
        if self.rect.left > SCREEN_WIDTH:
            self.kill()

pygame.init()

# The size is determined by the constant SCREEN_WIDTH and SCREEN_HEIGHT
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
clock=pygame.time.Clock()
#create custom event
ADDCAR_down= pygame.USEREVENT + 1
ADDCAR_up= pygame.USEREVENT + 2
pygame.time.set_timer(ADDCAR_up, spawnrate_up )
pygame.time.set_timer(ADDCAR_down, spawnrate_down )

#create car

car_up= pygame.sprite.Group()
car_down= pygame.sprite.Group()
car_down.add(Car_down(green,dimentions))
car_up.add(Car_up(green,dimentions))

#infinite loop
run = True

#MAIN

while run:

    # Look at every event in the queue
    for event in pygame.event.get():
    # Did the user hit a key?
        if event.type == KEYDOWN:
            # Was it the Escape key? If so, stop the loop.
            if event.key == K_ESCAPE:
                run = False


        # Did the user click the window close button? If so, stop the loop.

        elif event.type == QUIT:
            run = False

        elif event.type == ADDCAR_down:
        # Create the new CAR and add it to sprite groups
            new_car_down = Car_down(green,dimentions)
            car_down.add(new_car_down)

        elif event.type == ADDCAR_up:
            new_car_up = Car_up(green,dimentions)
            car_up.add(new_car_up)


    #grey screen
    screen.fill(grey)

    # Draw the car on the screen

    car_up.draw(screen)
    car_up.update()
    car_down.draw(screen)
    car_down.update()

    pygame.display.flip()
    clock.tick(25)
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Jrmnp
  • 25
  • 5

1 Answers1

1

You'll need to edit your Car_up.update() method to achieve the behaviour you want.

I added a self.timer attribute to the class, initial value fifty, to delay the car from resuming movement for two seconds after a collision. Then I handled the top-lane collision differently, only stopping the rear car.

Here's the new method:

# move car and delete once out of screen
def update(self):
    merge = random.randint(500, 1000)
    if self.rect.left > SCREEN_WIDTH:
        self.kill()
    intracollide = pygame.sprite.spritecollide(self, car_up, False)

    # stop if we've collided with the lower lane
    if pygame.sprite.spritecollide(self, car_down, False):
        self.speedx = self.speedy = 0
    elif len(intracollide) > 1:
        for car in intracollide:
            if car.rect.x > self.rect.x:  # only stop if we're the rear car
                self.speedx = self.speedy = 0
    elif self.rect.centery <= 263 and self.rect.centerx > merge:
        self.speedx = 10
        self.speedy = 3
    else:
        self.speedx = 10
        self.speedy = 0
    # decrement timer whilst stationary
    if self.speedx == 0:  
        self.timer -= 1
    if self.timer < 0:
        self.speedx = 10  # start moving after timer expires
        self.timer = 25  # reset timer to be shorter
    self.rect.move_ip(self.speedx, self.speedy)

This is still a little messy, but you should be able to extend the code to get closer to what you want.

Merging Cars

import random
  • 3,054
  • 1
  • 17
  • 22