Hoe detecteer ik een botsing in pygame?

Ik heb een lijst met opsommingstekens en een lijst met sprites gemaakt met behulp van de onderstaande klassen. Hoe kan ik detecteren of een kogel botst met een sprite en vervolgens die sprite en de kogel verwijderen?

#Define the sprite class
class Sprite:
    def __init__(self,x,y, name):
        self.x=x
        self.y=y
        self.image = pygame.image.load(name)
        self.rect = self.image.get_rect()
    def render(self):
        window.blit(self.image, (self.x,self.y))
# Define the bullet class to create bullets          
class Bullet:
    def __init__(self,x,y):
        self.x = x + 23
        self.y = y
        self.bullet = pygame.image.load("user_bullet.BMP")
        self.rect = self.bullet.get_rect()
    def render(self):
        window.blit(self.bullet, (self.x, self.y))

Antwoord 1, autoriteit 100%

In PyGame kan basisbotsingsdetectie worden gedaan met pygame.Rectobjecten. Het object rectbiedt verschillende methoden voor het detecteren van botsingen tussen objecten. Merk op dat zelfs de botsing van een rechthoekig object met een cirkelvormig object zoals een peddel en een bal in het spel Pongruwweg kan worden gedetecteerd door een botsing tussen twee rechthoekige objecten, de peddel en de begrenzende rechthoek van de bal.

Enkele voorbeelden:

  • pygame.Rect.collidepoint:

    Test of een punt binnen een rechthoek ligt

    repl.it/@Rabbid76/PyGame-collidepoint

    import pygame
    pygame.init()
    window = pygame.display.set_mode((250, 250))
    rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(100, 100)
    run = True
    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
        point = pygame.mouse.get_pos()
        collide = rect.collidepoint(point)
        color = (255, 0, 0) if collide else (255, 255, 255)
        window.fill(0)
        pygame.draw.rect(window, color, rect)
        pygame.display.flip()
    pygame.quit()
    exit()
    
  • pygame.Rect.colliderect

    Test of twee rechthoeken elkaar overlappen

    Zie ook Hoe u botsingen kunt detecteren tussen twee rechthoekige objecten of afbeeldingen in pygame

    repl.it/@Rabbid76/PyGame-colliderect

    import pygame
    pygame.init()
    window = pygame.display.set_mode((250, 250))
    rect1 = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
    rect2 = pygame.Rect(0, 0, 75, 75)
    run = True
    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
        rect2.center = pygame.mouse.get_pos()
        collide = rect1.colliderect(rect2)
        color = (255, 0, 0) if collide else (255, 255, 255)
        window.fill(0)
        pygame.draw.rect(window, color, rect1)
        pygame.draw.rect(window, (0, 255, 0), rect2, 6, 1)
        pygame.display.flip()
    pygame.quit()
    exit()
    

Verder pygame.Rect.collidelisten pygame.Rect.collidelistallkan worden gebruikt voor de botsingstest tussen een rechthoek en een lijst met rechthoeken. pygame.Rect.collidedicten pygame.Rect.collidedictallkan worden gebruikt voor de botsingstest tussen een rechthoek en een woordenboek van rechthoeken.

De botsing van pygame.sprite.Spriteen pygame.sprite.Groupkunnen worden gedetecteerd door pygame.sprite.spritecollide(), pygame.sprite.groupcollide()of pygame.sprite.spritecollideany(). Bij gebruik van deze methoden kan het algoritme voor botsingsdetectie worden gespecificeerd door het argument collided:

Het botsende argument is een callback-functie die wordt gebruikt om te berekenen of twee sprites botsen.

Mogelijke collidedcallables zijn collide_rect, collide_rect_ratio, collide_circle, collide_circle_ratio, collide_mask

Enkele voorbeelden:

  • pygame.sprite.spritecollide()

    repl.it/@Rabbid76/PyGame-spritecollide

    import pygame
    pygame.init()
    window = pygame.display.set_mode((250, 250))
    sprite1 = pygame.sprite.Sprite()
    sprite1.image = pygame.Surface((75, 75))
    sprite1.image.fill((255, 0, 0))
    sprite1.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
    sprite2 = pygame.sprite.Sprite()
    sprite2.image = pygame.Surface((75, 75))
    sprite2.image.fill((0, 255, 0))
    sprite2.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
    all_group = pygame.sprite.Group([sprite2, sprite1])
    test_group = pygame.sprite.Group(sprite2)
    run = True
    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
        sprite1.rect.center = pygame.mouse.get_pos()
        collide = pygame.sprite.spritecollide(sprite1, test_group, False)
        window.fill(0)
        all_group.draw(window)
        for s in collide:
            pygame.draw.rect(window, (255, 255, 255), s.rect, 5, 1)
        pygame.display.flip()
    pygame.quit()
    exit()
    

Voor een botsing met maskers zie Hoe kan ik een botsingsmasker?of Pygame-maskerbotsing

Zie ook Collision and Intersection

  • pygame.sprite.spritecollide()/ collide_circle

    repl.it/@Rabbid76/PyGame-spritecollidecollidecircle

    import pygame
    pygame.init()
    window = pygame.display.set_mode((250, 250))
    sprite1 = pygame.sprite.Sprite()
    sprite1.image = pygame.Surface((80, 80), pygame.SRCALPHA)
    pygame.draw.circle(sprite1.image, (255, 0, 0), (40, 40), 40)
    sprite1.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(40, 40)
    sprite2 = pygame.sprite.Sprite()
    sprite2.image = pygame.Surface((80, 89), pygame.SRCALPHA)
    pygame.draw.circle(sprite2.image, (0, 255, 0), (40, 40), 40)
    sprite2.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(80, 80)
    all_group = pygame.sprite.Group([sprite2, sprite1])
    test_group = pygame.sprite.Group(sprite2)
    run = True
    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
        sprite1.rect.center = pygame.mouse.get_pos()
        collide = pygame.sprite.spritecollide(sprite1, test_group, False, pygame.sprite.collide_circle)
        window.fill(0)
        all_group.draw(window)
        for s in collide:
            pygame.draw.circle(window, (255, 255, 255), s.rect.center, s.rect.width // 2, 5)
        pygame.display.flip()
    pygame.quit()
    exit()
    

Wat betekent dit allemaal voor je code?

pygame.Surface.get_rect.get_rect()retourneert een rechthoek met de grootte van het Surfaceobject, dat altijd begint bij (0, 0) aangezien een Surfaceobject geen positie heeft. De positie van de rechthoek kan worden gespecificeerd door een trefwoordargument. Het midden van de rechthoek kan bijvoorbeeld worden opgegeven met het trefwoordargument center. Dit trefwoordargument wordt toegepast op de attributen van de pygame.Rectvoordat het wordt geretourneerd (zie pygame.Rectvoor een volledige lijst van de trefwoordargumenten).
Zie *Waarom geeft mijn botsingstest altijd ‘true’ en waarom is de positie van de rechthoek van de afbeelding altijd verkeerd (0, 0)?

Je hebt de kenmerken xen yvan Spriteen Bullethelemaal niet nodig. Gebruik in plaats daarvan de positie van het kenmerk rect:

#Define the sprite class
class Sprite:
    def __init__(self, x, y, name):
        self.image = pygame.image.load(name)
        self.rect = self.image.get_rect(topleft = (x, y))
    def render(self):
        window.blit(self.image, self.rect)
# Define the bullet class to create bullets          
class Bullet:
    def __init__(self, x, y):
        self.bullet = pygame.image.load("user_bullet.BMP")
        self.rect = self.bullet.get_rect(topleft = (x + 23, y))
    def render(self):
        window.blit(self.bullet, self.rect)

Gebruik pygame.Rect.colliderect()om botsingen te detecteren tussen instanties van Spriteen Bullet.
Zie Hoe botsingen tussen twee rechthoekige objecten of Afbeeldingen in Pygame :

my_sprite = Sprite(sx, sy, name)
my_bullet = Bullet(by, by)
while True:
    # [...]
    if my_sprite.rect.colliderect(my_bullet.rect):
        printe("hit")

Antwoord 2, Autoriteit 46%

Vanaf wat ik begrijp van Pygame, hoeft u alleen maar te controleren of de twee rechthoeken elkaar overlappen met behulp van de colliderectMETHODE. Een manier om het te doen is om een ​​methode in uw BulletClass te hebben die controleert op botsingen:

def is_collided_with(self, sprite):
    return self.rect.colliderect(sprite.rect)

dan kunt u het noemen zoals:

sprite = Sprite(10, 10, 'my_sprite')
bullet = Bullet(20, 10)
if bullet.is_collided_with(sprite):
    print('collision!')
    bullet.kill()
    sprite.kill()

Antwoord 3, Autoriteit 14%

Er is een heel eenvoudige methode voor wat u probeert te doen met behulp van ingebouwde methoden.

hier is een voorbeeld.

import pygame
import sys
class Sprite(pygame.sprite.Sprite):
    def __init__(self, pos):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface([20, 20])
        self.image.fill((255, 0, 0))
        self.rect = self.image.get_rect()
        self.rect.center = pos
def main():
    pygame.init()
    clock = pygame.time.Clock()
    fps = 50
    bg = [255, 255, 255]
    size =[200, 200]
    screen = pygame.display.set_mode(size)
    player = Sprite([40, 50])
    player.move = [pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN]
    player.vx = 5
    player.vy = 5
    wall = Sprite([100, 60])
    wall_group = pygame.sprite.Group()
    wall_group.add(wall)
    player_group = pygame.sprite.Group()
    player_group.add(player)
    # I added loop for a better exit from the game
    loop = 1
    while loop:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                loop = 0
        key = pygame.key.get_pressed()
        for i in range(2):
            if key[player.move[i]]:
                player.rect.x += player.vx * [-1, 1][i]
        for i in range(2):
            if key[player.move[2:4][i]]:
                player.rect.y += player.vy * [-1, 1][i]
        screen.fill(bg)
        # first parameter takes a single sprite
        # second parameter takes sprite groups
        # third parameter is a do kill command if true
        # all group objects colliding with the first parameter object will be
        # destroyed. The first parameter could be bullets and the second one
        # targets although the bullet is not destroyed but can be done with
        # simple trick bellow
        hit = pygame.sprite.spritecollide(player, wall_group, True)
        if hit:
            # if collision is detected call a function in your case destroy
            # bullet
            player.image.fill((255, 255, 255))
        player_group.draw(screen)
        wall_group.draw(screen)
        pygame.display.update()
        clock.tick(fps)
    pygame.quit()
    # sys.exit
if __name__ == '__main__':
    main()

Antwoord 4

Maak een groep voor de opsommingstekens en voeg de opsommingstekens toe aan de groep.

Wat ik zou doen is dit:
In de klas voor de speler:

def collideWithBullet(self):
    if pygame.sprite.spritecollideany(self, 'groupName'):
        print("CollideWithBullet!!")
        return True

En ergens in de hoofdlus:

def run(self):
    if self.player.collideWithBullet():
         print("Game Over")

Hopelijk werkt dat voor jou!!!

Other episodes