簡體   English   中英

如何檢測 pygame 中的碰撞?

[英]How do I detect collision in pygame?

我使用下面的類制作了一個子彈列表和一個精靈列表。 如何檢測子彈是否與 sprite 發生碰撞,然后刪除該 sprite 和子彈?

#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))

在 PyGame 中,碰撞檢測是使用pygame.Rect對象完成的。 Rect對象提供了多種方法來檢測對象之間的碰撞。 甚至矩形和圓形物體(例如球拍和球)之間的碰撞也可以通過兩個矩形物體(球拍和球的邊界矩形)之間的碰撞來檢測。

一些例子:

  • pygame.Rect.collidepoint

    測試一個點是否在矩形內

    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

    測試兩個矩形是否重疊

    另請參閱如何在 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()

此外, pygame.Rect.collidelistpygame.Rect.collidelistall可用於矩形和矩形列表之間的碰撞測試。 pygame.Rect.collidedictpygame.Rect.collidedictall可用於矩形和矩形字典之間的碰撞測試。

pygame.sprite.Spritepygame.sprite.Group對象的碰撞,可以通過pygame.sprite.spritecollide()pygame.sprite.groupcollide()pygame.sprite.spritecollideany()檢測。 使用這些方法時,碰撞檢測算法可以由collided參數指定:

collided 參數是一個回調函數,用於計算兩個精靈是否發生碰撞。

可能的collided可調用對象是collide_rectcollide_rect_ratiocollide_circlecollide_circle_ratiocollide_mask

一些例子:

  • 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()

對於與掩碼的碰撞,請參閱如何制作碰撞掩碼? Pygame 蒙版碰撞

另見碰撞和相交

  • 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()

這對您的代碼意味着什么?

pygame.Surface.get_rect.get_rect()返回一個具有Surface對象大小的矩形,該矩形始終從 (0, 0) 開始,因為Surface對象沒有位置。 矩形的位置可以由關鍵字參數指定。 例如,可以使用關鍵字參數center指定矩形的中心。 這些關鍵字參數在返回之前應用於pygame.Rect的屬性(有關關鍵字參數的列表,請參見pygame.Rect )。
請參閱 * 為什么我的碰撞測試總是返回“真”,為什么圖像矩形的位置總是錯誤 (0, 0)?

您根本不需要SpriteBulletxy屬性。 改用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)

使用pygame.Rect.colliderect()來檢測SpriteBullet實例之間的碰撞。
請參閱如何在 pygame 中檢測兩個矩形對象或圖像之間的碰撞

my_sprite = Sprite(sx, sy, name)
my_bullet = Bullet(by, by)
while True:
    # [...]

    if my_sprite.rect.colliderect(my_bullet.rect):
        printe("hit")

根據我對 pygame 的了解,您只需要使用colliderect方法檢查兩個矩形是否重疊。 一種方法是在Bullet類中使用一個方法來檢查碰撞:

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

然后你可以這樣稱呼它:

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

對於您嘗試使用內置方法執行的操作,有一個非常簡單的方法。

這是一個例子。

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()

為項目符號創建一個組,然后將項目符號添加到該組。

我要做的是:在玩家的課堂上:

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

在某處的主循環中:

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

希望這對你有用!!!

在 Sprite 類中,嘗試添加一個self.mask屬性
self.mask = pygame.mask.from_surface(self.image)
和 Sprite 類內部的collide_mask函數,代碼如下:

    def collide_mask(self, mask):
        collided = False
        mask_outline = mask.outline()
        self.mask_outline = self.mask.outline()
        for point in range(len(mask_outline)):
            mask_outline[point] = list(mask_outline[point])
            mask_outline[point][0] += bullet.x
            mask_outline[point][1] += bullet.y
        for point in range(len(self.mask_outline)):
            self.mask_outline[point] = list(mask_outline[point])
            self.mask_outline[point][0] += self.x
            self.mask_outline[point][1] += self.y
        for point in mask_outline:
            for self_mask_point in self.mask_outline:
                if point = self_mask_point:
                    collided = True
        return collided

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM