लूप के लिए अन्य लूप के लिए अवरुद्ध

Nov 29 2020

मैं यह देखने के लिए मिसाइलग्रुप की जांच कर रहा हूं कि क्या मिसाइल के किसी भी उदाहरण के दुश्मनग्रुप में दुश्मन के किसी भी उदाहरण से टकरा गया है। जब चलाया जाता है, तो यह पहले लूप के लिए "हिट" प्रिंट करता है, लेकिन यह लूप के लिए दूसरे को अनदेखा करता है। ऐसा क्यों है?

 #### 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काम नहीं करेगा क्योंकि enemyGroupस्प्राइटग्रुप एक समूह के भीतर स्प्राइट्स की एक सूची है (शत्रुग्रुप <- शत्रुलिस्ट <- शत्रु (प्रेत)) स्प्राइट के एक समूह के बजाय (शत्रुग्रुप <- शत्रु (प्रेत))। मैं कैसे पहुंचूंगा?

अपडेट 2 @paxdiablo ने कहा कि पहला लूप शायद समूह को पुनरावृत्त करने के बाद खाली कर रहा है। मैंने छोरों के स्थानों को स्विच किया और 2 लूप चला, जबकि 1 नहीं था।

अद्यतन 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()

जवाब

Rabbid76 Nov 29 2020 at 21:21

देखें pygame.sprite.spritecollide():

समूह में सभी स्प्राइट युक्त सूची लौटाएं, जो किसी अन्य स्प्राइट के साथ प्रतिच्छेद करें।

इसलिए तर्क 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()1 लूप में कॉल करते हैं, तो दूसरा लूप काम नहीं करेगा, क्योंकि स्प्राइट को सभी समूहों से हटा दिया जाता है ।

तुम विधियों kill()में पुकारते हो resetmissile.reset()क्रमशः eachEnemy.reset()दूसरा लूप विफल होने का कारण बनता है।

paxdiablo Nov 29 2020 at 07:26

कोई स्पष्ट कारण नहीं है, प्रदान की गई जानकारी (ए) के आधार पर , दूसरी टक्कर की जांच विफल क्यों होनी चाहिए। अगर दुश्मन (7) और मिसाइल # 3 के बीच एक टक्कर है, तो मिसाइल # 3 और दुश्मन # 7 के बीच एक टक्कर भी होनी चाहिए ।

आप अपने स्वयं के (संभवत: गैर-कम्यूटेटिव) टक्कर फ़ंक्शन प्रदान करने जैसे किसी भी किनारे वाले सामान का उपयोग नहीं कर रहे हैं, इसलिए यह पता लगाने के लिए बस स्प्राइट आयत का उपयोग करेगा।

जब आप कोड में दो छोरों के क्रम को उल्टा करते हैं, तो मैं व्यवहार को देखने के लिए उत्सुक हूं ।


साथ ही, आपको उन समूह चर के प्रकारों को निर्दिष्ट करना चाहिए। यदि enemyGroupएक सूची एक समाप्त हो जनरेटर के बजाय की तरह कुछ कर रहे थे, यह होगा पहला पाश से "खाली कर दिया" किया और फिर दूसरी पाश पुनरावृति से अधिक के लिए कोई आइटम के लिए होता है (ख) ( 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दो छोरों के बीच अंतर करने के लिए एक उपयुक्त मूल्य का उपयोग करना ।


(ए) बेशक, हमेशा आपके द्वारा दी गई जानकारी की संभावना पूरी तरह से सही या पूर्ण नहीं है (कोई दुर्भावनापूर्ण इरादा नहीं है, लेकिन कभी-कभी लोग अनजाने में उन विवरणों को छोड़ देते हैं जिन्हें वे महत्वहीन विवरण मानते हैं , जो बहुत महत्वपूर्ण होने के कारण समाप्त होते हैं )।

उदाहरण: उन दो छोरों के बीच कुछ हो सकता है जो समस्या पैदा कर रहा है। मैं लोगों को संदेह का लाभ देना चाहूंगा, लेकिन आपको शायद हमें यह बताना चाहिए कि क्या ऐसा है।


(b) यह वास्तव में पहले लूप के पहले पुनरावृत्ति द्वारा खाली किया जाएगा ताकि आप पाएंगे कि यह शायद पहली मिसाइल के लिए कभी मेल खाएगा।

Kingsley Nov 29 2020 at 07:51

यहां एक त्वरित उदाहरण है जो दिखाता है (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()