【问题标题】:pygame bitmask collision won't workpygame位掩码冲突不起作用
【发布时间】:2013-04-14 17:12:38
【问题描述】:

虽然当我使用pygame.sprite.collide_rectpygame.sprite.collide_circle 时检测到碰撞,但当我尝试为精灵分配位掩码并按此方式运行时,未检测到碰撞。 (wall.collision_action() 使第一个圆圈以与另一个圆圈相同的速度和方向移动)虽然现在这不是问题,
因为我正在使用使 pygame.sprite.collide_circle 工作正常的圆圈图像,所以将来当我使用更详细和非圆形的精灵时,它将是。

代码:

import pygame, sys, math
from pygame.locals import *
pygame.init()

class ball_class(pygame.sprite.Sprite):
    def __init__(self, surface):
        self.surface = surface
        self.x = 250
        self.y = 250
        self.vy = 0
        self.vx = 0
        self.sprite = pygame.sprite.Sprite()
        self.sprite.image = pygame.image.load("ball.png").convert()
        self.sprite.rect = self.sprite.image.get_rect(center = (self.x, self.y))
        self.sprite.rect.topleft = [int(self.x), int(self.y)]
        self.sprite.mask = pygame.mask.from_surface(self.sprite.image)

    def event(self, event):
        if event.key == K_UP:
            self.vy = -1
            self.vx = 0
        elif event.key == K_DOWN:
            self.vy = 1
            self.vx = 0
        elif event.key == K_LEFT:
            self.vx = -1
            self.vy = 0
        elif event.key == K_RIGHT:
            self.vx = 1
            self.vy = 0

    def move(self):
        self.y += self.vy
        self.x += self.vx
        self.sprite.rect.topleft = [int(self.x), int(self.y)]
        self.sprite.mask = pygame.mask.from_surface(self.sprite.image)

    def draw(self, surface):
        surface.blit(self.sprite.image, self.sprite.rect)

    def position(self):
        return self.sprite.rect()

class wall_class(pygame.sprite.Sprite):
    def __init__(self, surface):
        self.surface = surface
        self.x = 250
        self.y = 100
        self.vy = 0
        self.sprite = pygame.sprite.Sprite()
        self.sprite.image = pygame.image.load("ball.png").convert()
        self.sprite.rect = self.sprite.image.get_rect(center = (self.x, self.y))
        self.sprite.rect.topleft = [int(self.x), int(self.y)]
        self.sprite.mask = pygame.mask.from_surface(self.sprite.image)

    def draw(self, surface):
        surface.blit(self.sprite.image, self.sprite.rect)

    def collision_action(self):
        self.vy = ball.vy
        self.vx = ball.vx
        self.x += self.vx
        self.y += self.vy
        self.sprite.rect.topleft = [int(self.x), int(self.y)]

def gameQuit():
    pygame.quit()
    sys.exit()

screen = pygame.display.set_mode((500, 500), 0, 32)
ball = ball_class(screen)
wall = wall_class(screen)
clock = pygame.time.Clock()
while True:
    screen.fill((0, 0, 0))
    ball.move()
    ball.draw(screen)
    wall.draw(screen)
    is_a_collision = pygame.sprite.collide_mask(wall.sprite, ball.sprite)
    if is_a_collision:

        wall.collision_action()

    for event in pygame.event.get():
        if event.type == QUIT:
            gameQuit()
        elif event.type == KEYDOWN:
            ball.event(event)
    clock.tick(100)
    pygame.display.update()

【问题讨论】:

  • 你的代码有很多问题。我建议您阅读 Python 中类的一般用法,然后阅读 pygame 中的 sprite 类,然后阅读遮罩的工作原理。并真正深入阅读。在stackoverflow上要回答的问题太多了。
  • 是的,可能有很多问题,但目前我只尝试修复一个。我将从解决方案倒推到完全理解所有内容。
  • 我假设“ball.png”已经具有透明度?
  • 你的面具有些问题。尝试调用wall.sprite.mask.outline(),您会注意到它返回一个空列表。与ball.sprite 中的掩码相同。你在这里做了一些非常奇怪的事情(比如扩展Sprite,但是不是填充普通的Sprite属性,而是在扩展的Sprite对象上创建一个Sprite属性,然后向其中添加属性......) .

标签: python pygame sprite collision


【解决方案1】:

位掩码冲突在您的代码中起作用,但我认为代码使其变得更加困难,因为精灵对象 ball_classwall_class 在其中定义了单独的子精灵对象.

class ball_class(pygame.sprite.Sprite):
    def __init__(self, surface):
        self.surface = surface
        self.x = 250
        self.y = 250
        self.vy = 0
        self.vx = 0
        self.sprite = pygame.sprite.Sprite()    # <-- HERE
        ...

通常,当代码“子类化”一个现有的类/对象时,它变成其中之一。所以没有必要在类中包含次要精灵。这也使得代码和逻辑更加复杂、复杂和混乱。

请考虑重新处理您的ball_class

class ball_class(pygame.sprite.Sprite):
    def __init__(self, surface):
        pygame.sprite.Sprite.__init__(self)    # <-- HERE Must initialise sprites
        self.x     = 250
        self.y     = 250
        self.vy    = 0
        self.vx    = 0
        self.image = pygame.image.load("ball_64.png").convert_alpha()
        self.rect  = self.image.get_rect(center = (self.x, self.y))
        self.mask  = pygame.mask.from_surface(self.image)

注意imagerectmask 成员变量。以前的代码是使用这些关闭包含的精灵。但是 PyGame 库被编写为期望这些作为类的成员,如果没有定义它们就不能正常工作。此外,您的两个精灵类没有调用基本精灵初始化函数。

这是对您的代码的重新处理,当球撞到墙角时,会正确碰撞(使用位掩码)。

ball_64.png

wall.png

import pygame, sys, math
from pygame.locals import *
pygame.init()

class ball_class(pygame.sprite.Sprite):
    def __init__(self, surface):
        pygame.sprite.Sprite.__init__(self)
        self.surface = surface
        self.x = 250
        self.y = 250
        self.vy = 0
        self.vx = 0
        self.image = pygame.image.load("ball_64.png").convert_alpha()
        self.rect  = self.image.get_rect(center = (self.x, self.y))
#        self.sprite.rect.topleft = [int(self.x), int(self.y)]
        self.mask = pygame.mask.from_surface(self.image)

    def event(self, event):
        if event.key == K_UP:
            self.vy = -1
            self.vx = 0
        elif event.key == K_DOWN:
            self.vy = 1
            self.vx = 0
        elif event.key == K_LEFT:
            self.vx = -1
            self.vy = 0
        elif event.key == K_RIGHT:
            self.vx = 1
            self.vy = 0

    def move(self):
        self.y += self.vy
        self.x += self.vx
        self.rect.topleft = [int(self.x), int(self.y)]
        #self.mask = pygame.mask.from_surface(self.sprite.image)

    def draw(self, surface):
        surface.blit(self.image, self.rect)

    def position(self):
        return self.rect()

class wall_class(pygame.sprite.Sprite):
    def __init__(self, surface):
        pygame.sprite.Sprite.__init__(self)
        self.x = 250
        self.y = 100
        self.vy = 0
        self.image = pygame.image.load("wall.png").convert_alpha()
        self.rect  = self.image.get_rect(center = (self.x, self.y))
#        self.sprite.rect.topleft = [int(self.x), int(self.y)]
        self.mask = pygame.mask.from_surface( self.image )

    def draw(self, surface):
        surface.blit(self.image, self.rect)

    def collision_action(self, by_sprite_at ):
        print("wall_class.collision_action( by_sprite_at=%s )" % ( str( by_sprite_at ) ) )
#        self.vy = ball.vy
#        self.vx = ball.vx
#        self.x += self.vx
#        self.y += self.vy
#        self.sprite.rect.topleft = [int(self.x), int(self.y)]

def gameQuit():
    pygame.quit()
    sys.exit()

screen = pygame.display.set_mode((500, 500), 0, 32)
ball = ball_class(screen)
wall = wall_class(screen)
clock = pygame.time.Clock()
while True:
    screen.fill((128,128,128))
    ball.move()
    ball.draw(screen)
    wall.draw(screen)
    is_a_collision = pygame.sprite.collide_mask(wall, ball)
    if is_a_collision:
        wall.collision_action( ball.rect.center )

    for event in pygame.event.get():
        if event.type == QUIT:
            gameQuit()
        elif event.type == KEYDOWN:
            ball.event(event)
    clock.tick(100)
    pygame.display.update()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-24
    相关资源
    最近更新 更多