Pygame,同一组中2个对象之间的碰撞

时间:2018-06-06 16:53:49

标签: python pygame collision

所以,我正在尝试创建一个游戏,外星人从3个特定的地方产卵。每个外星人将在3中的一个中随机产生。但是总会有至少一个外星人,它会在另一个上面产生。我想删除那个外星人并在另一个产卵点随机产生他。如果它是空的,他将留下,否则将重复该过程。问题是我无法找到一种方法来检测同一组中2个对象的碰撞。

我刚开始学习pygame所以1)我的问题可能是愚蠢的2)我的产卵方式可能是非常低效的

这是异形课程:

class Alien(pygame.sprite.Sprite):
def __init__(self):
    pygame.sprite.Sprite.__init__(self)
    self.image = pygame.Surface((80,60))
    self.image.fill(GREY)
    self.rect = self.image.get_rect()
    spawn_point1 = x1,y1 = -30, 70
    spawn_point2 = x2,y2 = -30, 150
    spawn_point3 = x3,y3 = -30, 230
    random_spawn = random.choice([spawn_point1,spawn_point2,spawn_point3])
    self.rect.center = random_spawn
    self.speedx = 10

def update(self):
    spawn_point1 = x1,y1 = -30, 70
    spawn_point2 = x2,y2 = -30, 150
    spawn_point3 = x3,y3 = -30, 230
    self.speedx = 10
    random_spawn = random.choice([spawn_point1,spawn_point2,spawn_point3])
    self.rect.x += self.speedx

    if self.rect.x > WIDTH + 20:
        self.rect.center = random_spawn

这是我检测碰撞的部分(这部分不起作用)

aliens_col = pygame.sprite.groupcollide(aliens, aliens, True, False)

for i in aliens_col:
    alien = Alien()
    aliens.add(alien)
    all_sprites.add(aliens)

3 个答案:

答案 0 :(得分:0)

这是Bounding Box测试的一个实现。

import random


class Rectangle:

    def __init__(self, height, width, x, y):
        self.height = height
        self.width = width
        self.x = x
        self.y = y

    def collided_with_another_rectangle(self, rect):
        """ Assumes rectangles are same size or that this rectangle is smaller than the other rectangle"""
        if self.x > (rect.x + rect.width):
            # Is to the right of the other rectangle
            return False
        elif (self.x + self.width) < rect.x:
            # is to the left of the other rectangle
            return False
        elif (self.y + self.height) < rect.y:
            # is above the other rectangle
            return False
        elif self.y > (rect.y + rect.height):
            # is below the other rectangle
            return False
        else:
            return True


collision_count = 0
for i in range(0, 1000):
    # Here I pick random locations on a 1000X1000 screen for the first rectangle 
    x1 = random.randint(0, 1000)
    y1 = random.randint(0, 1000)
    # Here I pick random locations on a 1000X1000 screen for the second rectangle 
    rect1 = Rectangle(100, 100, x1, y1)
    x2 = random.randint(0, 1000)
    y2 = random.randint(0, 1000)
    rect2 = Rectangle(100, 100, x2, y2)
    """
     I use the collided with another rectangle function to test if the first rectangle is above,below, 
     to the right or to the left of the other rectangle. If neither of these are true then the rectangles 
     have collided.
    """
    if rect1.collided_with_another_rectangle(rect2):
        collision_count += 1
        print("Rect1 X and Y:" + str(x1) + " " + str(y1))
        print("Rect2 X and Y:" + str(x2) + " " + str(y2))
        print("collided")

print("Collision Count:" + str(collision_count))

答案 1 :(得分:0)

我仍然不能确定你想要达到的目标,但我认为这个例子会对你有所帮助。

当精灵离开屏幕时,我调用reset_pos方法,在其中迭代三个生成点,将位置设置为另一个生成,然后我使用另一个for循环迭代精灵检查是否发生碰撞。

如果精灵碰撞,我继续下一个生成点。

如果没有sprite碰撞,我只是从方法返回。

如果没有spawn是免费的,我会删除精灵(但你可以做其他事情)。

import random

import pygame
from pygame.math import Vector2


pygame.init()
WIDTH, HEIGHT = 640, 480


class Alien(pygame.sprite.Sprite):

    def __init__(self, aliens):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((80, 60))
        self.image.fill((120, random.randrange(255), random.randrange(255)))
        self.rect = self.image.get_rect()
        self.spawn_points = [(-30, 70), (-30, 150), (-30, 230)]
        self.aliens = aliens
        self.reset_pos()
        self.speedx = 10

    def update(self):
        self.rect.x += self.speedx

        if self.rect.x > WIDTH + 20:
            self.reset_pos()

    def reset_pos(self):
        random.shuffle(self.spawn_points)  # Shuffle the spawns.

        for spawn in self.spawn_points:
            # Set the position to one of the spawns.
            self.rect.center = spawn
            # Check if this sprite collides with another one.
            for sprite in self.aliens:
                if sprite is self:  # Skip self.
                    continue
                if self.rect.colliderect(sprite.rect):
                    break  # Break out of the loop if the spawn is occupied.
            else:  # The else means no 'break' occurred in the for loop above,
                   # so the spawn must be free.
                return  # Break out of the method if the spawn is free.

        # I just remove the sprite if no spawn is free. You can do something else here.
        self.kill()


def main():
    screen = pygame.display.set_mode((640, 480))
    clock = pygame.time.Clock()
    aliens = pygame.sprite.Group()
    for _ in range(3):
        # I pass the aliens group to the sprite because we need to
        # iterate over it to see if a sprite collides.
        alien = Alien(aliens)
        aliens.add(alien)
    all_sprites = pygame.sprite.Group(aliens)

    done = False

    while not done:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True
            elif event.type == pygame.MOUSEBUTTONDOWN:
                  al = Alien(aliens)
                  all_sprites.add(al)
                  aliens.add(al)

        all_sprites.update()

        screen.fill((30, 30, 30))
        all_sprites.draw(screen)

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


if __name__ == '__main__':
    main()
    pygame.quit()

答案 2 :(得分:0)

当在 groupcollide 的两个组参数中使用相同的组时,它总是认为它在 group_a 中检查的精灵与 group_b 中的同一个精灵发生碰撞。这导致 groupcollide 总是返回一个碰撞。

为了解决这个问题,我在 pygame 的 sprite.py 中创建了一个新函数,它忽略单个碰撞并且只返回碰撞 >= 2。我唯一的改变是添加:

if len(collision) >=2:

然后是以下行所需的选项卡。

我添加到 sprite.py 的代码粘贴在下面,但 defintra_groupcollide 的选项卡太远了:

def intra_groupcollide(groupa, groupb, dokilla, dokillb, collided=None):
"""detect collision between a group and itself.
This is modified from groupcollide but excludes collisions <=1

pygame.sprite.groupcollide(groupa, groupb, dokilla, dokillb):
    return dict

"""
crashed = {}
# pull the collision function in as a local variable outside
# the loop as this makes the loop run faster
sprite_collide_func = spritecollide
if dokilla:
    for group_a_sprite in groupa.sprites():
        collision = sprite_collide_func(group_a_sprite, groupb,
                                        dokillb, collided)
        if collision:
            if len(collision) >=2:
                crashed[group_a_sprite] = collision
                group_a_sprite.kill()
else:
    for group_a_sprite in groupa:
        collision = sprite_collide_func(group_a_sprite, groupb,
                                        dokillb, collided)
        if collision:
            if len(collision) >=2:
                crashed[group_a_sprite] = collision



                
            
#print(crashed)
return crashed

然后在我自己的python程序中,我简单地将groupcollide替换为intra_groupcollide。我将两个 kill 参数都设置为“false”,因为在我的用法中,我将它们相互弹开。我还没有在将它们设置为“true”的情况下测试此代码。

我按照以下答案在我的文件系统中找到了 sprite.py: Where are the python modules stored?