Pygame 面具碰撞只会在第一次碰撞时造成伤害

问题描述

我正在编写一个简单的入侵者游戏。为了增加对底座的伤害,我想我可以在子弹撞击时在底座上闪烁一个小的黑色表面,然后使用面罩检查子弹是否在损坏处或底座上,但它不起作用,我觉得我我误解了面具。检测到第一次碰撞但之后它也检测到碰撞但不会对底座造成更多损坏。我认为因为表面是黑色的,所以基本面罩不会包含它,但它不起作用。这是一个简短的测试来演示这个。按空格键(或任意键)向底部发射子弹。我想也许我应该为基础生成一个新的掩码,但这不起作用。 mask collide来自github上的pygame sprite代码

import sys,pygame,random
from pygame.locals import *

screenwidth = 600
screenheight = 400

pygame.init()
screen = pygame.display.set_mode((screenwidth,screenheight))
pygame.display.set_caption("shoot 'em up")

screenrect = screen.get_rect()

black = (0,0)

blue = (10,10,255)
yellow = (238,238,0)

base_width = 80
base_height = 40

bullet_width = 3
bullet_height = 10

class Bullet(pygame.Surface):
    
    def __init__(self,point):
        super().__init__((bullet_width,bullet_height),pygame.SRCALPHA)
        self.rect = self.get_rect()
        self.rect.midbottom = point
        self.fill(yellow)
        self.veLocity = -5
        self.alive = True
        self.mask = pygame.mask.from_surface(self)
            
    def update(self):
        
        self.rect.top += self.veLocity
        
    def draw(self,surf):
        surf.blit(self,self.rect)

class Base(pygame.Surface):

    def __init__(self,x,y,colour):
        super().__init__((base_width,base_height),pygame.SRCALPHA)
        self.rect = self.get_rect()
        self.rect.x = x
        self.rect.y = y 
        self.fill(colour)
        self.alive = True
        
    def add_damage(self,bullet):
        width = random.randint(3,6)
        height = random.randint(8,12)
        damage = pygame.Surface((width,height),pygame.SRCALPHA)
        damage.fill(black)
        rect = damage.get_rect()
        rect.x = bullet.rect.x - self.rect.x
        rect.y = bullet.rect.top - self.rect.top 
        self.blit(damage,rect)
        #self.mask = pygame.mask.from_surface(self) 
    
    def draw(self,self.rect)
        
class Test(pygame.Surface):

    def __init__(self):
        super().__init__((600,400))

        self. base = Base(50,300,blue)
        self.bullets = []
        
    def run(self):
    
        while 1:
            self.get_events()
            self.update()
            self.draw()
                
    def get_events(self):

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            
            if event.type == pygame.KEYDOWN:
                bullet = Bullet((60,380))
                self.bullets.append(bullet)
                    
    def update(self):
        if self.bullets:
            for bullet in self.bullets:
                bullet.update()
                self.collision_check(bullet)
            
            for bullet in self.bullets:
                if not bullet.alive:
                    self.bullets.remove(bullet)
                    
    def collision_check(self,bullet):
        if bullet.rect.colliderect(self.base):
            if self.collide_mask(bullet,self.base):
                print("collide")
                self.base.add_damage(bullet)
                bullet.alive = False
                
    def collide_mask(self,left,right):

        xoffset = right.rect[0] - left.rect[0]
        yoffset = right.rect[1] - left.rect[1]

        try:
            leftmask = left.mask
        except AttributeError:
            leftmask = pygame.mask.from_surface(left)
        try:
            rightmask = right.mask
        except AttributeError:
            rightmask = pygame.mask.from_surface(right)
    
        return leftmask.overlap(rightmask,(xoffset,yoffset))

    def draw(self):
        self.fill(black)
        self.base.draw(self)
        
        for bullet in self.bullets:
            bullet.draw(self)
            
        screen.blit(self,(0,0))
        
        pygame.display.flip()
        
if __name__=="__main__":
    t = test()
    t.run()

正如你所看到的,这不是使用 pygame 精灵。

解决方法

如果更改了 pygame.Surface 对象,您需要使用 pygame.mask.from_surface 重新创建掩码。但是,遮罩是从 Surface 的 alpha 通道生成的。因此,您需要使损坏的区域透明。创建一个完全透明的矩形(RGBA = 0,0)并使用特殊标志 BLEND_RGBA_MULT(或 BLEND_RGBA_MINblit 矩形。最后重新创建掩码:

damage = pygame.Surface((width,height),pygame.SRCALPHA)
self.blit(damage,rect,special_flags=pygame.BLEND_RGBA_MULT)
self.mask = pygame.mask.from_surface(self) 

add_damage 方法:

class Base(pygame.Surface):
    # [...]

    def add_damage(self,bullet):
        width = random.randint(3,6)
        height = random.randint(8,12)
        damage = pygame.Surface((width,pygame.SRCALPHA)
        rect = damage.get_rect()
        rect.x = bullet.rect.x - self.rect.x
        rect.y = bullet.rect.top - self.rect.top 
        self.blit(damage,special_flags=pygame.BLEND_RGBA_MULT)
        self.mask = pygame.mask.from_surface(self)