1
import pygame, time, random

pygame.init()

display_width = 800
display_height = 600

white = (255,255,255)
green = (0,255,0)
black = (0,0,0)

gameDisplay = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()

boy = pygame.image.load("pig.png")
fence = pygame.image.load("fence.png")

def message_display(text):
    largeText = pygame.font.Font("freesansbold.ttf",115)
    TextSurf, TextRect = text_objects(text, largeText)
    TextRect.center = (display_width/2),(display_height/2)
    gameDisplay.blit(TextSurf, TextRect)
    pygame.display.update()
    time.sleep(2)
    game_loop()
def text_objects(text, font):
    textSurface = font.render(text, True, black)
    return textSurface, textSurface.get_rect()
def crash():
    message_display("Game Over")
def fence1(fencex, fencey, fencew, fenceh, color):
    gameDisplay.blit(fence, (fencex, fencey, fencew, fenceh))
def collision():
    pig_image = pygame.image.load("pig.png")
    pig_rect = pig_image.get_rect()
    fence_image = pygame.image.load("fence.png")
    fence_rect = fence_image.get_rect()
    if pig_rect.colliderect(fence_rect):
        crash()
def game_loop():
    fence_startx = 900
    fence_starty = gameDisplay.get_height() * 0.8
    fence_speed = 15
    fence_width = 50
    fence_height = 50

    x = gameDisplay.get_width() * 0.1
    y = gameDisplay.get_height() * 0.8
    y_change = 0
    on_ground = True
    gravity = .9

    gameExit = False

    while not gameExit:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    if on_ground:
                        y_change = -20
                        on_ground = False

        y_change += gravity
        y += y_change
        if y >= 500:
            y = 500
            y_change = 0
            on_ground = True

        gameDisplay.fill(green)
        gameDisplay.blit(boy, (x, y))
        fence1(fence_startx, fence_starty, fence_width, fence_height, white)
        fence_startx -= fence_speed
        randomx = random.randint(1,3)

        if fence_startx <= -50:
            if randomx == 1:
                fence_startx = 1000
            if randomx == 2:
                fence_startx = 800
            if randomx == 3:
                fence_startx = 1500

        collision()

        pygame.display.flip()

        clock.tick(60)

game_loop()
pygame.quit()
quit()

For some reason when I run this code, it spams me "Game Over". Could someone please help me on this issue. I use a collision function in this code. Is using the pygame.rect code the best way to do collision in pygame? Everything works except for my collision in the game. I would greatly appreciate some help. Thanks.

5
  • 2
    To see what's happening, examine the rects you're testing for collision, for instance using print. Commented Oct 14, 2017 at 0:11
  • @molbdnilo Yes, I have already done this and it just puts the results out rapidly every frame. Commented Oct 14, 2017 at 1:20
  • 1
    Look at your collision() function. From what I can tell, it looks like you are loading two images from two png files. When images are loaded, they default to a rect of the form (x, y, image_width, image_height) where (x, y) is (0, 0). Therefore, it is unsurprising that your two rects are overlapping and colliding if they both have their top-left corners at (0, 0)! Commented Oct 14, 2017 at 7:01
  • @CodeSurgeon Thanks, but how would I add the x,y to the rects? Commented Oct 14, 2017 at 13:57
  • 1
    You could do something like my_rect.rect.x = new_x_value. I would look at the answer @skrx provided though, it should answer your questions more thoroughly! Commented Oct 14, 2017 at 14:54

1 Answer 1

2

In the collision function you create two rects but leave their coordinates at the default position (0, 0) so the rects overlap. You should add rects for the player and the fence in the main game_loop function, set their x and y (or the topleft) attributes to the desired coordinates and then update them every iteration of the while loop. To check if the rects collide, pass them to the collision function and do this:

def collision(boy_rect, fence_rect):
    if boy_rect.colliderect(fence_rect):
        # I'm just printing it to shorten the code example.
        print('crash')

Here's a minimal, complete example:

import random
import pygame


pygame.init()

green = (0,255,0)

gameDisplay = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()

boy = pygame.Surface((40, 60))
boy.fill((0, 40, 100))
fence = pygame.Surface((50, 50))
fence.fill((100, 60, 30))


def collision(boy_rect, fence_rect):
    if boy_rect.colliderect(fence_rect):
        # I'm just printing it to shorten the code example.
        print('crash')


def game_loop():
    fence_speed = 15
    # Create a fence and a boy rect and set their x,y or topleft coordinates.
    fence_rect = fence.get_rect()
    fence_rect.x = 900
    fence_rect.y = gameDisplay.get_height() * 0.8

    x = gameDisplay.get_width() * 0.1
    y = gameDisplay.get_height() * 0.8
    boy_rect = boy.get_rect(topleft=(x, y))

    y_change = 0
    on_ground = True
    gravity = .9

    gameExit = False

    while not gameExit:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                gameExit = True
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    if on_ground:
                        y_change = -20
                        on_ground = False

        y_change += gravity
        y += y_change
        if y >= 500:
            y = 500
            y_change = 0
            on_ground = True
        boy_rect.y = y  # Update the rect position.

        gameDisplay.fill(green)
        gameDisplay.blit(boy, boy_rect)
        gameDisplay.blit(fence, fence_rect)
        # Update the position of the fence rect.
        fence_rect.x -= fence_speed

        if fence_rect.x <= -50:
            # You can use random.choice to pick one of these values.
            fence_rect.x = random.choice((800, 1000, 1500))
        # Pass the two rects and check if they collide.
        collision(boy_rect, fence_rect)

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

game_loop()
pygame.quit()
Sign up to request clarification or add additional context in comments.

4 Comments

I got this error when trying to blit the rects to the screen. TypeError: argument 1 must be pygame.Surface, not pygame.Rect
You can't blit pygame.Rects, only pygame.Surfaces. The rects are just used to store the position/coordinates and the size of your objects. For example, to blit the fence surface/image at the fence_rect coordinates just write: gameDisplay.blit(fence, fence_rect).
I did this and the errors are gone, but it still does not work.
Either post a new question if this bug is unrelated or add your updated code to this question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.