다른 For 루프를 차단하는 For 루프
missileGroup을 확인하여 미사일 인스턴스가 적군의 인스턴스 적과 충돌했는지 확인합니다. 실행되면 첫 번째 루프에 대해 "Hit"을 인쇄하지만 두 번째 for 루프는 무시합니다. 왜 그런 겁니까?
#### 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")
업데이트 : @ Rabbid76은 spritecollide
spriteGroup enemyGroup
이 스프라이트 그룹 (enemyGroup <-Enemy (sprite))이 아닌 그룹 (enemyGroup <-enemyList <-Enemy (sprite)) 내의 스프라이트 목록 이기 때문에 작동하지 않을 것이라고 말했습니다 . 어떻게 액세스 할 수 있습니까?
업데이트 2 @paxdiablo는 첫 번째 루프가 반복 후 그룹을 비울 수 있다고 말했습니다. 나는 루프의 위치를 바꾸고 두 번째 루프가 실행되었지만 첫 번째 루프는 실행되지 않았습니다.
업데이트 3 전체 코드 에서 그룹에서 스프라이트를 제거하는 .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()
답변
참조 pygame.sprite.spritecollide():
다른 Sprite와 교차하는 그룹의 모든 Sprite를 포함하는 목록을 반환합니다.
따라서 인수 spritecollide()
는 pygame.sprite.Sprite객체와 객체 여야 pygame.sprite.Group합니다. 그룹 대신 개체
목록이 작동하지 않습니다.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")
더 읽어보기 kill()
스프라이트가 포함 된 모든 그룹 에서 제거됩니다 .
따라서 kill()
첫 번째 루프 를 호출 하면 스프라이트가 모든 그룹 에서 제거되기 때문에 두 번째 루프가 작동하지 않습니다 .
당신은 전화 kill()
에 reset
방법. missile.reset()
각각 eachEnemy.reset()
두 번째 루프가 실패합니다.
제공된 정보 (a)를 기반으로 두 번째 충돌 검사가 실패해야하는 이유는 분명 하지 않습니다. 예를 들어 적 # 7과 미사일 # 3 사이에 충돌이 발생하면 미사일 # 3과 적 # 7 사이 에도 충돌이 발생 해야합니다 .
당신은 자신의 (비교 류적) 충돌 함수를 제공하는 것과 같은 엣지 케이스를 사용하지 않으므로 단순히 스프라이트 직사각형을 사용하여 이것을 감지합니다.
코드에서 두 루프의 순서 를 반대로 하면 동작을보고 싶습니다 .
또한 이러한 그룹 변수의 유형을 지정해야합니다. enemyGroup
목록이 아니라 소진 가능한 생성기와 같은 것이면 첫 번째 루프에 의해 "비워지고"두 번째 루프에는 반복 할 항목이 없습니다 (b) ( spritecollide
호출은 각 항목을 확인하기 위해 그룹을 반복합니다. 스프라이트에 대해).
그것은 spritecollide
당신이 설명하는 효과를 볼 수 있는 유일한 방법이며 버그 그 자체가 부족 합니다.
예를 들어, 다음은 생성기를 두 번 반복하는 코드입니다.
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) 실제로 첫 번째 루프의 첫 번째 반복 에 의해 비워 지므로 아마도 첫 번째 미사일에만 일치 할 것임을 알 수 있습니다.
다음은이보고 된 동작이 발생하지 않음을 보여주는 간단한 예입니다 (PyGame 1.9.6에서).
이 예는 두 개의 생성 스프라이트 그룹을 그런 다음에 그들을 충돌 정확한 영업 이익의 예제 코드와 동일한 방법.
프린팅과 마찬가지로 스프라이트는 충돌에 참여했다고 믿는지 여부에 따라 윤곽선-> 채워진 상태에서 변경됩니다. 미사일과 충돌하는 적의 1 : 1 매핑이 있으며 그 반대도 마찬가지입니다.
프레임 속도가 좋지 않아 사과드립니다 ...

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