For循环阻塞其他For循环

2024-07-04 17:23:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在检查导弹群,看看是否有导弹与敌人群中的敌人发生碰撞。运行时,它为第一个循环打印“命中”,但忽略第二个循环。为什么呢

 #### Imagine this is in a game loop ####
    for missile in missileGroup:
        if pygame.sprite.spritecollide(missile, enemyGroup, False) :
            print("Hit")

    
    for enemy in enemyGroup:
        if pygame.sprite.spritecollide(enemy, missileGroup, False):
            print("HI")

更新:@rabbi76声明spritecollide不起作用,因为精灵组enemyGroup是一个组(enemyGroup<;-enemyList<;-敌军(sprite))中的精灵列表,而不是一组精灵(enemyGroup<;-敌军(sprite))。我该如何访问它

更新2@paxdiablo声明第一个循环可能在迭代后清空组。我切换了循环的位置,第二个循环运行,而第一个循环没有

update3在完整的代码中,.reset()方法运行.kill(),从组中删除精灵。由于第一个循环在第二个循环检测不到任何碰撞之前移除导弹精灵:

for missile in missileGroup:
    if pygame.sprite.spritecollide(missile, enemyGroup, False) :
        missile.reset()

for eachEnemy in enemyGroup: 
        if pygame.sprite.spritecollide(eachEnemy, missileGroup, False):
            eachEnemy.reset()

Tags: inltfalseforifpygame精灵reset
3条回答

下面是一个快速的例子,表明(在PyGame 1.9.6中)这种报告的行为不会发生

该示例创建两个sprite groups,然后以与OP示例代码相同的方式碰撞它们

与打印一样,精灵也会从大纲->;填充,取决于他们是否认为自己参与了碰撞。有一个1:1的敌人与导弹相撞的地图,反之亦然

抱歉帧速率太低。。。 collision_demo

import pygame
import random

# Window size
WINDOW_WIDTH    = 800
WINDOW_HEIGHT   = 800

DARK_BLUE = (   3,   5,  54 )
RED       = ( 200,   0,   0 )
YELLOW    = ( 240, 250,   0 )
BLACK     = (   0,   0,   0 )
GREY      = ( 200, 200, 200 )
GREEN     = ( 250,   0,   0 )
TRANSPARENT=( 0,0,0,0 )


class Shape(pygame.sprite.Sprite):
    def __init__(self, width=48, height=48):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface( ( width, height ), pygame.SRCALPHA)
        self.rect  = self.image.get_rect()
        # Start position is randomly across the screen, and a little off the top
        self.rect.center = ( random.randrange( 0, WINDOW_WIDTH ), random.randrange( 0, WINDOW_HEIGHT ) )
        # Movement
        self.dx = random.randrange( -2, 2 )
        self.dy = random.randrange( -2, 2 )
        # Looks like
        self.filled = 2
        self.last_fill = -1
        self.render()

    def setFilled( self, value ):
        if ( value == True ):
            self.filled = 0
        else:
            self.filled = 2

    def update( self ):
        if ( self.last_fill != self.filled ):
            self.last_fill = self.filled
            self.render()

        self.rect.move_ip( self.dx, self.dy )

        if ( self.rect.left > WINDOW_WIDTH ):
            self.rect.x = -self.rect.width
        elif ( self.rect.right < 0 ):
            self.rect.left = WINDOW_WIDTH
        if ( self.rect.y > WINDOW_HEIGHT ):
            self.rect.y = 0
        elif ( self.rect.y < 0 ):
            self.rect.y = WINDOW_HEIGHT


class Square( Shape ):
    def render( self ):
        # Something to draw

        if ( self.filled == 0 ):
            self.image.fill( RED )
        else:
            border=3
            x, y = border, border
            width = self.rect.width - border -1
            height = self.rect.height - border -1
            self.image.fill( TRANSPARENT )
            pygame.draw.rect( self.image, RED, (x,y,width,height), self.filled )

class Circle( Shape ):
    def render( self ):
        self.image.fill( TRANSPARENT )
        pygame.draw.circle( self.image, YELLOW, (self.rect.width//2, self.rect.height//2), self.rect.width//2, self.filled )




### initialisation
pygame.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ) )

### Some sprite groups
missileGroup = pygame.sprite.Group()
for i in range( 3 ):
    new_missile = Circle()
    new_missile.render()
    missileGroup.add( Circle() )

enemyGroup = pygame.sprite.Group()
for i in range( 12 ):
    new_enemy = Square()
    new_enemy.render()
    enemyGroup.add( Square() )


### Main Loop
clock = pygame.time.Clock()
done = False
while not done:

    # Handle user-input
    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            done = True
        elif ( event.type == pygame.MOUSEBUTTONUP ):
            # On mouse-click
            pass
    # Move * collide the sprites
    missileGroup.update()
    enemyGroup.update()

    # Test Collisions
    for missile in missileGroup:
        if pygame.sprite.spritecollide(missile, enemyGroup, False) :
            print("Missile " + str(missile) + " Hits Enemy")
            missile.setFilled( True )
        else:
            missile.setFilled( False )

    for enemy in enemyGroup:
        if pygame.sprite.spritecollide(enemy, missileGroup, False):
            print("Enemy  " + str(enemy) + " Hits Missile")
            enemy.setFilled( True )
        else:
            enemy.setFilled( False )


    # Paint the window, but not more than 60fps
    window.fill( DARK_BLUE )
    enemyGroup.draw( window )
    missileGroup.draw( window )
    pygame.display.flip()


    # Clamp FPS
    clock.tick(60)


pygame.quit()

根据提供的信息,(a),没有明显的原因说明第二次碰撞检查失败的原因。如果(例如)敌方7号导弹和敌方3号导弹发生碰撞,则3号导弹和敌方7号导弹也应该发生碰撞

您没有使用任何像提供您自己的(可能是非交换的)碰撞函数这样的边缘情况,因此它只会使用精灵矩形来检测这个

我很想看看当你把代码中两个循环的顺序颠倒过来时的行为


此外,还应指定这些组变量的类型。如果enemyGroup类似于一个可耗尽的生成器而不是一个列表,那么它将被第一个循环“清空”,然后第二个循环将没有可迭代的项(b)(调用spritecollide将迭代组以对照精灵检查每个项)

除了spritecollide本身的bug之外,这是唯一一种可以看到您所描述的效果的方法


作为示例,这里有一段代码尝试在生成器上迭代两次:

class gen3(object):
    def __init__(self): self._num = 0
    def __iter__(self): return self
    def __next__(self):
        if self._num == 3: raise StopIteration()
        self._num += 1
        return self._num - 1

gen = gen3()
print("A: ")
for i in gen: print(" ", i)
print("B: ")
for i in gen: print(" ", i)

输出显示第二个循环不执行任何操作:

A:
  0
  1
  2
B:

最后,检查组状态的确定方法是在每个循环之前简单地放置以下代码:

print("loop X enemy  ", len(enemyGroup),   enemyGroup)
print("loop X missile", len(missileGroup), missileGroup)

使用合适的X值来区分这两个循环


(a)当然,总有一种可能性你提供的信息不完全准确或不完整(没有恶意意图,但有时人们会无意中跳过他们认为不重要的细节,最终变得非常重要)

示例:这两个循环之间可能发生了导致问题的事情。我更愿意让人们相信这种怀疑,但如果是这样的话,你可能应该让我们知道


(b)它实际上会在第一个循环的第一次迭代中被清空,所以你会发现它可能只会与第一枚导弹匹配

^{}

Return a list containing all Sprites in a Group that intersect with another Sprite.

因此spritecollide()的参数必须是^{}对象和^{}对象。
pygame.sprite.Sprite对象列表代替不起作用

missileGroup = pygame.sprite.Group()
enemyGroup = pygame.sprite.Group()
for missile in missileGroup:
    if pygame.sprite.spritecollide(missile, enemyGroup, False):
        print("Hit")

for enemy in enemyGroup:
    if pygame.sprite.spritecollide(enemy, missileGroup, False):
        print("HI")

进一步了解^{}

The Sprite is removed from all the Groups that contain it.

因此,如果在第一个循环中调用kill(),第二个循环将不起作用,因为精灵将从所有组中移除

reset方法中调用kill()missile.reset()分别{}导致第二个循环失败

相关问题 更多 >

    热门问题