pygame/sprites: 暴徒碰撞

pygame/sprites: mob collision

您好,我最近开始接触 pygame 库并制作一些小项目。我正在制作一个非常简单的游戏,你作为玩家必须躲避敌人。但是,我想在它们相互碰撞时删除它们。我想到了下面的代码,但是,它只删除了一个小怪。生物在 all_sprites 和 mob_sprites 中。我对精灵和 pygame 很陌生,所以这里可能有一个愚蠢的错误,希望有人能帮助我。

# check mob collision
for mob in mobs:
    temp_sprites.add(mob)
    mobs.remove(mob)
    collision = pg.sprite.groupcollide(temp_sprites, mobs, True, True)
    for col in collision:
        # score is just for the game
        score += col.size
    else:
        mobs.add(mob)
        all_sprites.add(mob)

    temp_sprites.remove(mob)

如果你想销毁一个精灵,调用pygame.sprite.Sprite.kill():

就足够了
mob.kill()

kill 从包含它的所有组中删除 Sprite。

如果你想检测一个精灵是否与循环中的任何其他精灵发生碰撞,那么我建议使用 2 个嵌套循环和 pygame.sprite.collide_rect():

例如:

for mob1 in mobs:
    for mob2 in mobs:
        
        if mob1 != mob2 and pg.sprite.collide_rect(mob1, mob2):
            mob1.kill()
            mob2.kill()

            # score is just for the game
            score += col.size

你的第一个问题是你使用了一个for...else循环; else 部分将被执行,如果你不 break for 循环以防发生碰撞,从而重新添加精灵。

你的代码的第二个问题是,虽然 groupcollide 会正确地从它们的组中删除精灵,但它们将被重新添加,因为它们仍然存储在你用 [=18 迭代的列表中=] 循环(遍历精灵组每次都会创建一个新列表)。

所以你可以用这样的方法修复你的代码:

    for mob in mobs.sprites():
        
        if not mob.groups():
            # mob was already removed by a previous iteration of this loop
            continue

        temp_sprites.add(mob)
        mobs.remove(mob)
        collision = pygame.sprite.groupcollide(temp_sprites, mobs, True, True)
        for col in collision:
            # score is just for the game
            score += col.size
            break
        else:
            mobs.add(mob)
            all_sprites.add(mob)

        temp_sprites.remove(mob)

但我建议改为在精灵的 update 方法中处理碰撞。

def update(self):
    # whatever
    if pygame.sprite.spritecollide(self, self.mobs, True, collide_rect_not_self):
        self.kill()

其中 self.mobs 是对 mobs 组的引用,collide_rect_not_self 是对 pygame.sprite.collide_rect:

的简单包装
def collide_rect_not_self(a, b):
    if a != b:
        return pygame.sprite.collide_rect(a, b)

这是一个完整的例子:

import random
import pygame

def collide_rect_not_self(a, b):
    if a != b:
        return pygame.sprite.collide_rect(a, b)

class Actor(pygame.sprite.Sprite):
    def __init__(self, pos, mobs, static, *grps):
        super().__init__(mobs, *grps)
        self.image = pygame.Surface((40, 40))
        self.rect = self.image.get_rect(center=pos)
        self.pos = pygame.Vector2(*pos)
        self.vel = pygame.Vector2(random.randint(0, 10), random.randint(0, 10)) if not static else pygame.Vector2(0, 0)
        self.mobs = mobs

    def update(self):
        self.pos += self.vel
        if not pygame.display.get_surface().get_rect().contains(self.rect):
            self.vel *= -1
            self.rect.clamp_ip(pygame.display.get_surface().get_rect())
            self.pos = self.rect.center
        self.rect.center = self.pos
        if pygame.sprite.spritecollide(self, self.mobs, True, collide_rect_not_self):
            self.kill()

def main():
    pygame.init()
    clock = pygame.time.Clock()
    screen = pygame.display.set_mode((800, 600))
    mobs = pygame.sprite.Group()
    all_sprites = pygame.sprite.Group()
    while True:

        for event in pygame.event.get():
            pos = pygame.mouse.get_pos()
            if event.type == pygame.QUIT:
                return

            if event.type == pygame.MOUSEBUTTONDOWN:
                Actor(event.pos, mobs, event.button == 1, all_sprites)
                    
        screen.fill((255, 255, 255))
        all_sprites.update()
        all_sprites.draw(screen)
        clock.tick(30)
        
               
        pygame.display.flip()
main()

使用鼠标左键放置静态矩形,使用其他鼠标按钮放置移动矩形。