Pygame 精灵重叠问题 [英] Pygame sprites overlapping issue

查看:62
本文介绍了Pygame 精灵重叠问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在自学python,并从一个简单的pygame游戏开始.到目前为止,游戏包括一个被其他球追赶的球,我创建了一个循环,避免追球重叠.循环的工作方式是通过嵌套循环移动通过包含所有追逐球的列表,然后测量它们之间的距离,如果距离小于球半径,则将其移开.它似乎在大部分时间都有效,但有时球会重叠.我不知道为什么,如果有人可以看看我的代码并给我一个提示,我会很感激它,我认为错误发生在有 3 个以上的球和球员的球 (pelota) 碰撞的那一刻.

i'm learning python by myself, and started with a simple game with pygame. The game consists, so far, in a ball that's been chased by other balls, i have created a loop that avoid the chasing balls to overlap. The way the loop works its by a nested loop that moves thru a list that includes all the chasing balls, then measures the distance between them, if the distance is less than the ball radius, it is moved away. It seems to work most of the time, but sometimes a ball overlaps. I dont know why, if anyone can take a look at my code and give me a hint i would apreciate it, i think the error happens when there are more than 3 balls and at the moment when the player's ball (pelota) collides.

import pygame, random, math
pygame.init()

ancho , alto = 800 , 600
negro = (0,0,0)
blanco=(255,255,255)
FPS = 60     
velocidad = 7
velocidadnalguis = velocidad - 2
contadordecolisiones = 1
perseguidores =  []

pantalla=pygame.display.set_mode((ancho,alto))
pygame.display.set_caption("un jueguito")
reloj=pygame.time.Clock()

class Pelota(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("pelota.png").convert()
        self.image = pygame.transform.scale(self.image, (30, 30))
        self.image.set_colorkey(negro)
        self.rect = self.image.get_rect()
        self.rect.center = (ancho/2,alto/2) 
        self.speed = 0

    def update(self):
        self.speedx = 0
        self.speedy = 0
        tecla  = pygame.key.get_pressed()
        
        if tecla[pygame.K_LEFT]:
            self.speedx = -velocidad
        
        if tecla[pygame.K_RIGHT]:
            self.speedx = velocidad      

        if tecla[pygame.K_UP]:
            self.speedy = -velocidad

        if tecla[pygame.K_DOWN]:
            self.speedy = velocidad

        self.rect.x += self.speedx
        self.rect.y += self.speedy

        if self.rect.right > ancho:
            self.rect.right = ancho

        if self.rect.bottom > alto:
            self.rect.bottom = alto

        if self.rect.left < 0:
            self.rect.left = 0

        if self.rect.top < 0:
            self.rect.top = 0

pelota = Pelota()

class Perseguidor(pygame.sprite.Sprite):
    def __init__(self,):
        super().__init__()
        self.image = pygame.image.load('nalguis.png').convert()
        self.image = pygame.transform.scale(self.image, (30, 30))
        self.image.set_colorkey(negro)
        self.rect = self.image.get_rect()
        self.velocidad = velocidadnalguis
        self.radius = self.rect.width/2
        self.center = self.rect.center
        self.contadordecolisiones = 1
        self.enerandom = random.randint(0,4)

        if self.enerandom == 0:
             self.rect.center = (random.randrange(-130,-30),random.randrange(-130,alto+130))
        if self.enerandom == 1:
             self.rect.center = (random.randrange(-130,ancho+130),random.randrange(-130,-30))
        if self.enerandom == 2:
             self.rect.center = (random.randrange(ancho+30,ancho+130),random.randrange(-130,alto+130))
        if self.enerandom == 3:
            self.rect.center = (random.randrange(-130,ancho+130),random.randrange(alto+30,alto+130))

    def update(self):
        
        self.pely = pelota.rect.y
        self.pelx = pelota.rect.x
        self.perx = self.rect.x
        self.pery = self.rect.y

        self.dist = math.sqrt(((self.pely-self.pery)**2) + ((self.pelx-self.perx)**2))/velocidadnalguis

        self.angulo = math.atan2(self.pely-self.pery,self.pelx-self.perx)

        self.speedx = 0
        self.speedy = 0
        self.speedx = math.cos(self.angulo) 
        self.speedy = math.sin(self.angulo) 
        
        if self.dist>=1:
            self.rect.x += velocidadnalguis * self.speedx
            self.rect.y += velocidadnalguis * self.speedy

all_sprites = pygame.sprite.Group()
perseguidor_grupo = pygame.sprite.Group()
all_sprites.add(pelota)

terminar=False

while not terminar:
    reloj.tick(FPS)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            terminar=True
    
    if len(perseguidor_grupo)<1:
        perseguidor=Perseguidor()
        perseguidor_grupo.add(perseguidor)
        all_sprites.add(perseguidor)

    hit = pygame.sprite.spritecollide(pelota, perseguidor_grupo, True, pygame.sprite.collide_circle)

    if hit: 
        
        if len(perseguidor_grupo)<25:
            perseguidor = Perseguidor()
            perseguidor1 = Perseguidor()
            all_sprites.add(perseguidor, perseguidor1)
            perseguidor_grupo.add(perseguidor, perseguidor1)
            perseguidores.append(perseguidor1)
            perseguidores.append(perseguidor)
            
        else :
            perseguidor = Perseguidor()
            all_sprites.add(perseguidor)
            perseguidor_grupo.add(perseguidor)
            perseguidores.append(perseguidor)
        
    dist=1
    
    for i in  range (len(perseguidores)):
        for j in range(i+1,len(perseguidores)):
            perseguidoresxy = [perseguidores[i].rect.centerx,perseguidores[i].rect.centery]
            dist=math.hypot(perseguidores[i].rect.centerx - perseguidores[j].rect.centerx , perseguidores[i].rect.centery - perseguidores[j].rect.centery)
                            
            if dist <= perseguidor.radius*2:
                if perseguidores[i].rect.centerx < perseguidores[j].rect.centerx:
                    perseguidores[i].rect.centerx -= 3
                if perseguidores[i].rect.centery < perseguidores[j].rect.centery:
                    perseguidores[i].rect.centery -= 3
                if perseguidores[i].rect.centerx > perseguidores[j].rect.centerx:
                    perseguidores[i].rect.centerx += 3  
                if perseguidores[i].rect.centery > perseguidores[j].rect.centery:   
                    perseguidores[i].rect.centery -= 3
                                        
    if len(perseguidores)> len(perseguidor_grupo):
        del perseguidores [0]       
    
    all_sprites.update()
    pantalla .fill(negro)
    all_sprites.draw(pantalla)
    
    pygame.display.flip()
    
pygame.quit()
quit()

推荐答案

[...] 然后测量它们之间的距离,如果距离小于球半径,则将其移开.它似乎在大部分时间都有效,但有时球会重叠.[...]

[...] then measures the distance between them, if the distance is less than the ball radius, it is moved away. It seems to work most of the time, but sometimes a ball overlaps. [...]

当然.你在移动一个球时只考虑 2 个球.这意味着如果您将一个球从一个球上移开,您可能会将它直接移到另一个球上.您需要检查您移动球的位置是否没有其他球.

Of course.You only consider 2 balls when moving a ball away. This means that if you move a ball away from one ball, it can happen that you move it straight onto another ball. You need to check that there is no other ball in the position where you are moving the ball.

确保球在生成时不会重叠:

Make sure the balls don't overlap as they spawn:

requested_balls = 1

while not terminar:
    # [...]

    hit = pygame.sprite.spritecollide(pelota, perseguidor_grupo, True, pygame.sprite.collide_circle)
    if hit: 
        requested_balls = min(25, requested_balls+1)
    if len(perseguidor_grupo) < requested_balls:
        perseguidor = Perseguidor()
        if not pygame.sprite.spritecollide(perseguidor, perseguidor_grupo, True, pygame.sprite.collide_circle):
            all_sprites.add(perseguidor)
            perseguidor_grupo.add(perseguidor)
            perseguidores.append(perseguidor)

仅当球的新位置尚未被球占据时才移动球:

Only move a ball if the new position of the ball is not yet occupied by a ball:

class Perseguidor(pygame.sprite.Sprite):
    # [...]

    def update(self):
        # [...]

        old_rect = self.rect.copy()
        if self.dist>=1:
            self.rect.x += velocidadnalguis * self.speedx
            self.rect.y += velocidadnalguis * self.speedy

        hit = pygame.sprite.spritecollide(self, perseguidor_grupo, False, pygame.sprite.collide_circle)
        if len(hit) > 1: # at last 1, because the ball hits itself
            if random.randrange(2) == 0:
                self.rect.x = old_rect.x
            else:
                self.rect.y = old_rect.y
            hit = pygame.sprite.spritecollide(self, perseguidor_grupo, False, pygame.sprite.collide_circle)
            if len(hit) > 1:
                    self.rect = old_rect

完整示例:

import pygame, random, math
pygame.init()

ancho , alto = 800 , 600
negro = (0,0,0)
blanco=(255,255,255)
FPS = 60     
velocidad = 7
velocidadnalguis = velocidad - 2
contadordecolisiones = 1
perseguidores =  []

pantalla=pygame.display.set_mode((ancho,alto))
pygame.display.set_caption("un jueguito")
reloj=pygame.time.Clock()

class Pelota(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("pelota.png").convert()
        self.image = pygame.transform.scale(self.image, (30, 30))
        self.image.set_colorkey(negro)
        self.rect = self.image.get_rect()
        self.rect.center = (ancho/2,alto/2) 
        self.speed = 0

    def update(self):
        self.speedx = 0
        self.speedy = 0
        tecla  = pygame.key.get_pressed()
        
        if tecla[pygame.K_LEFT]:
            self.speedx = -velocidad
        
        if tecla[pygame.K_RIGHT]:
            self.speedx = velocidad      

        if tecla[pygame.K_UP]:
            self.speedy = -velocidad

        if tecla[pygame.K_DOWN]:
            self.speedy = velocidad

        self.rect.x += self.speedx
        self.rect.y += self.speedy

        if self.rect.right > ancho:
            self.rect.right = ancho

        if self.rect.bottom > alto:
            self.rect.bottom = alto

        if self.rect.left < 0:
            self.rect.left = 0

        if self.rect.top < 0:
            self.rect.top = 0

pelota = Pelota()

class Perseguidor(pygame.sprite.Sprite):
    def __init__(self,):
        super().__init__()
        self.image = pygame.image.load('nalguis.png').convert()
        self.image = pygame.transform.scale(self.image, (30, 30))
        self.image.set_colorkey(negro)
        self.rect = self.image.get_rect()
        self.velocidad = velocidadnalguis
        self.radius = self.rect.width/2
        self.center = self.rect.center
        self.contadordecolisiones = 1
        self.enerandom = random.randint(0,4)

        if self.enerandom == 0:
             self.rect.center = (random.randrange(-130,-30),random.randrange(-130,alto+130))
        if self.enerandom == 1:
             self.rect.center = (random.randrange(-130,ancho+130),random.randrange(-130,-30))
        if self.enerandom == 2:
             self.rect.center = (random.randrange(ancho+30,ancho+130),random.randrange(-130,alto+130))
        if self.enerandom == 3:
            self.rect.center = (random.randrange(-130,ancho+130),random.randrange(alto+30,alto+130))

    def update(self):
        
        self.pely = pelota.rect.y
        self.pelx = pelota.rect.x
        self.perx = self.rect.x
        self.pery = self.rect.y

        self.dist = math.sqrt(((self.pely-self.pery)**2) + ((self.pelx-self.perx)**2))/velocidadnalguis

        self.angulo = math.atan2(self.pely-self.pery,self.pelx-self.perx)

        self.speedx = 0
        self.speedy = 0
        self.speedx = math.cos(self.angulo) 
        self.speedy = math.sin(self.angulo) 
        
        old_rect = self.rect.copy()
        if self.dist>=1:
            self.rect.x += velocidadnalguis * self.speedx
            self.rect.y += velocidadnalguis * self.speedy

        hit = pygame.sprite.spritecollide(self, perseguidor_grupo, False, pygame.sprite.collide_circle)
        if len(hit) > 1: # at last 1, because the ball hits itself
            if random.randrange(2) == 0:
                self.rect.x = old_rect.x
            else:
                self.rect.y = old_rect.y
            hit = pygame.sprite.spritecollide(self, perseguidor_grupo, False, pygame.sprite.collide_circle)
            if len(hit) > 1:
                    self.rect = old_rect

        

all_sprites = pygame.sprite.Group()
perseguidor_grupo = pygame.sprite.Group()
all_sprites.add(pelota)

terminar=False

requested_balls = 1

while not terminar:
    reloj.tick(FPS)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            terminar=True
    
    if len(perseguidor_grupo)<1:
        perseguidor=Perseguidor()
        perseguidor_grupo.add(perseguidor)
        all_sprites.add(perseguidor)

    hit = pygame.sprite.spritecollide(pelota, perseguidor_grupo, True, pygame.sprite.collide_circle)
    if hit: 
        requested_balls = min(25, requested_balls+1)
    if len(perseguidor_grupo) < requested_balls:
        perseguidor = Perseguidor()
        if not pygame.sprite.spritecollide(perseguidor, perseguidor_grupo, True, pygame.sprite.collide_circle):
            all_sprites.add(perseguidor)
            perseguidor_grupo.add(perseguidor)
            perseguidores.append(perseguidor)
        
    dist=1
                                        
    if len(perseguidores)> len(perseguidor_grupo):
        del perseguidores [0]       
    
    all_sprites.update()
    pantalla .fill(negro)
    all_sprites.draw(pantalla)
    
    pygame.display.flip()
    
pygame.quit()
quit()

这篇关于Pygame 精灵重叠问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆