Come rilevare le collisioni tra due oggetti o immagini rettangolari in pygame

Aug 24 2020

Sto realizzando un gioco in cui il giocatore deve usare una ciotola per raccogliere oggetti che cadono. Ho alcune immagini di oggetti in un elenco e un'immagine di una ciotola che viene utilizzata per catturare gli oggetti. Gli oggetti continuano a cadere e si ripristinano nella parte superiore dello schermo se raggiungono il confine (bordo inferiore). Ho fatto questa logica che consente agli oggetti di cadere ma non so come rilevare quando c'è una collisione tra la ciotola e l'oggetto.

Il mio codice:

import math
import pygame
import random


pygame.init()

display_width = 800
display_height = 600

game_display = pygame.display.set_mode((display_width, display_height))
clock = pygame.time.Clock()
pygame.display.set_caption("Catch the Ball")

white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 255, 0)

player_img = pygame.image.load("Images/soup.png")
thing_imgs = [pygame.image.load('Images/muffin.png'), pygame.image.load('Images/dessert.png'),
              pygame.image.load('Images/cheese.png'), pygame.image.load('Images/fruit.png')]


def player(x, y):
    game_display.blit(player_img, (x, y))


def things(x, y, img):
    game_display.blit(img, (x, y))


def game_loop():
    running = True

    x = display_width * 0.45
    y = display_height * 0.8
    x_change = 0

    player_width = 64
    player_height = 64

    things_cor = [[random.randint(0, display_width), 32]]
    things_added = [random.choice(thing_imgs)]
    thing_height = 32
    thing_width = 32
    y_change = 5

    caught = 0

    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    x_change = -5

                if event.key == pygame.K_RIGHT:
                    x_change = 5

            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                    x_change = 0

        game_display.fill(white)

        player(x, y)
        x += x_change

        for i in range(len(things_cor)):
            thing_x, thing_y = things_cor[i]
            things(thing_x, thing_y, things_added[i])

        for i in range(len(things_cor)):
            things_cor[i][1] += y_change
            if things_cor[i][1] > display_height:
                things_cor[i][1] = random.randint(-2000, -1000)
                things_cor[i][0] = random.randint(0, display_width)
                things_added[i] = random.choice(thing_imgs)

                things_added.append(random.choice(thing_imgs))

                if len(things_added) < 6:
                    things_cor.append(
                        [random.randint(0, display_width), -10])

        if x < 0:
            x = 0
        elif x > display_width - player_width:
            x = display_width - player_width

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


game_loop()

Risposte

5 Rabbid76 Aug 24 2020 at 19:33

Usa pygame.Rectoggetti e colliderect()per rilevare la collisione tra i rettangoli di delimitazione di 2 oggetti o 2 immagini:

rect1 = pygame.Rect(x1, y1, w1, h1)
rect2 = pygame.Rect(x2, y2, w2, h2)
if rect1.colliderect(rect2):
    # [...]

Se devi immagini ( pygame.Surfaceoggetti), è possibile recuperare il rettangolo di delimitazione get_rect(), dove la posizione della superficie deve essere impostata da un argomento parola chiave, poiché il rettangolo restituito inizia sempre da (0, 0):
(vedi Perché è il mio test di collisione non funziona e perché la posizione del rettangolo dell'immagine è sempre sbagliata (0, 0)? )

def game_loop():
    # [...]

    while running:
        # [...]

        player_rect = player_img.get_rect(topleft = (x, y))
        for i in range(len(things_cor)):
            thing_rect = things_added[i].get_rect(topleft = things_cor[i])

            if player_rect.colliderect(thing_rect):
                print("hit")

        player(x, y)
        x += x_change

        for i in range(len(things_cor)):
            thing_x, thing_y = things_cor[i]
            things(thing_x, thing_y, things_added[i]) 

Utilizzare pygame.time.get_ticks()per ritardare l'inizio del gioco per un certo tempo. pygame.time.get_ticks()restituisce il numero di millisecondi da quando è pygame.init()stato chiamato. Per esempio:

def game_loop():
    # [...]

    while running:
        passed_time = pygame.time.get_ticks() # passed time in milliseconds
        start_time = 100 * 1000 # start time in milliseconds (100 seconds)
        
        # [...]

        # move player    
        if passed_time >= start_time:
            x += x_change
            if x < 0:
                x = 0
            elif x > display_width - player_width:
                x = display_width - player_width
    
        # move things
        if passed_time >= start_time:
            for i in range(len(things_cor)):
                things_cor[i][1] += y_change
                if things_cor[i][1] > display_height:
                    things_cor[i][1] = random.randint(-2000, -1000)
                    things_cor[i][0] = random.randint(0, display_width)
                    things_added[i] = random.choice(thing_imgs)

                    things_added.append(random.choice(thing_imgs))

                    if len(things_added) < 6:
                        things_cor.append(
                            [random.randint(0, display_width), -10])

        # draw scene and update dispaly
        game_display.fill(white)
        player(x, y)
        for i in range(len(things_cor)):
            thing_x, thing_y = things_cor[i]
            things(thing_x, thing_y, things_added[i])
        pygame.display.update()
        clock.tick(60)