微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Python pygame精灵碰撞检测如何通过减少点来定义哪个精灵与组碰撞并影响其属性

如何解决Python pygame精灵碰撞检测如何通过减少点来定义哪个精灵与组碰撞并影响其属性

尝试做的是创建一个Arkanoid游戏,其中砖头各自具有3点强度,然后它们死亡。问题在于,失去整个积分的不仅仅是brick击中特定的砖,而是整个brick_sprite组。当一个人想死的时候,列表中所有以前的人都死了。我认为问题在于它会循环考虑第240行的更新。请检查def collision(self):类下Brick处的65行。问题在那儿。

"""This is a simple version of arkanoid game"""

import sys
import pygame
import random


# Set colors R G B
white = (255,255,255)
black = (0,0)
orange = (255,100,10)
light_blue = (0,144,255)
shadow = (192,192,192)
purple = (152,152)

# display
display_height = 999
display_width = 444
pygame.display.set_caption = ("Arkanoid 1.0")
FPS = 60

# Movement speed
speed = display_width // 60

# Movements
left = (-speed,0)
right = (speed,0)
up = (0,speed)
diagonal_left = [-speed,-speed]
diagonal_right = [speed,-speed]

# Game objects dimentions
base_dimentions = (display_width // 5,display_height // 100)
[brick_width,brick_height] = [display_width // 20 * 2,display_height // 100]
brick_dimentions = [brick_width,brick_height] 
ball_dimentions = (display_height // 100,display_height // 100)

# Initializing text font
pygame.font.init()
txt_font = pygame.font.SysFont("score: ",display_height//44)

# Initializing sprite lists
all_sprites = pygame.sprite.Group()
brick_sprites = pygame.sprite.Group()


class Brick(pygame.sprite.Sprite):

    def __init__(self,point_value,center):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface(brick_dimentions)
        self.image.fill(purple)
        self.rect = self.image.get_rect()
        self.rect.center = center
        self.point_value = point_value

    def update(self):
        self.collision()

    def collision1(self): #This works no issue.
        # If brick is hit,loses a point
        collision = pygame.sprite.spritecollide(ball,brick_sprites,True)
        return collision

    def collision(self): #Here is the issue.
        # If brick is hit,False)
        if collision:
            self.point_value -= 1
            if self.point_value == 0:
                self.kill() ## BUGGISH ##"""

class Ball(pygame.sprite.Sprite):
    """Initiates a moving ball and its' attributes"""

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface(ball_dimentions)
        self.image.fill(light_blue)
        self.rect = self.image.get_rect()
        self.rect.center = self.init_position()
        self.direction = random.choice([diagonal_left,diagonal_right])
        self.score = 0

    def update(self):
        self.movement()

    def init_position(self):
        # Initialize position of the ball
        init_position = (board.rect.center[0],(board.rect.center[1] - (base_dimentions[1] / 2)
                          - (ball_dimentions[1] / 2)))
        return init_position

    def collision(self):
        # If hit bricks
        collision = pygame.sprite.spritecollideany(ball,brick_sprites)
        if collision:
            self.direction[1] *= -1
            self.score += 1
    enter code here
    def movement(self):
        self.containment()
        self.rect[1] += self.direction[1]
        self.rect[0] += self.direction[0]
        self.deflect()
        self.ball_loss()
        self.collision()

    def containment(self):
        if self.rect.right >= display_width or self.rect.left <= 0:
            self.direction[0] *= -1
        if self.rect.top <= 0:
            self.direction[1] *= -1

    def ball_loss(self):
        if self.rect.bottom >= display_height:
            self.reset()
            bricks_reset()

    def reset(self):
        self.rect.center = self.init_position()
        self.direction[1] *= -1
        self.score = 0

    def deflect(self):
        # If hit base_board,deflect
        if (self.rect.bottom == board.rect.top and
            (board.rect.left <= self.rect.left <= board.rect.right or
             board.rect.left <= self.rect.right <= board.rect.right)):
            self.direction[1] *= -1
            self.board_ball_interaction()

    def board_ball_interaction(self):
        # When board is moving,effects balls direction/speed
        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_LEFT] and board.rect.left > 0:
            self.direction[0] -= speed // 2
        elif keystate[pygame.K_RIGHT] and board.rect.right < display_width:
            self.direction[0] += speed // 2


class Base_board(pygame.sprite.Sprite):
    """Initiates base_board class and it's attributes"""

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface(base_dimentions)
        self.image.fill(orange)
        self.rect = self.image.get_rect()
        self.rect.center = (display_width // 2,display_height - 2 * base_dimentions[1])
        self.x_direction = 0

    def update(self):
        # Up-dates classes' position according to user's imput
        self.x_direction = 0
        self.movement()
        self.rect.x += self.x_direction

    def movement(self):
        # Creates movement and constrains object within screen dimentions
        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_LEFT]:
            if not self.rect.left <= 0:
                self.x_direction = -speed
        elif keystate[pygame.K_RIGHT]:
            if not self.rect.right >= display_width:
                self.x_direction = speed

    def shoot(self):
        pass

    def enlogate(self):
        pass


def control():

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()


# and adding all sprites on lists
board = Base_board()
ball = Ball()

all_sprites.add(board)
all_sprites.add(ball)


def bricks_list_creator():
    # Creates and adds bricks into a list
    i = 9
    point_value = 2 ####
    coordinates = [display_width // 20 + brick_width / 6,display_height // 20]
    while i > 0:
        brick = Brick(point_value,(coordinates)) ####
        coordinates[0] += brick_width * 1.1
        brick_sprites.add(brick)
        i -= 1
    return brick_sprites


def bricks_reset():
    # Reset brick list
    brick_sprites.empty()
    bricks_list_creator()
    return brick_sprites


def render_text(screen):
    text = txt_font.render("score: {0}".format(ball.score),1,(0,0))
    return screen.blit(text,(5,10))


def render_main(screen):
    all_sprites.draw(screen)
    brick_sprites.draw(screen)
    render_text(screen)


# Game main
def main():
    pygame.init()

    clock = pygame.time.Clock()
    screen = pygame.display.set_mode((display_width,display_height))
    bricks_list_creator()

    while True:

        # Events
        clock.tick(FPS)
        control()

        # Update
        brick_sprites.update()
        all_sprites.update()

        # Render
        screen.fill(shadow)
        render_main(screen)
        pygame.display.flip()
        pygame.display.update()


main()

解决方法

我认为问题出在调用冲突的update()类的Brick中。

子画面更新功能通常用于更改子画面的位置或外观,称为每帧。因此,它不是检查碰撞的好地方。

Brick仅需要知道其point_value,它就不会移动(AFAIK)。

class Brick(pygame.sprite.Sprite):

    def __init__(self,point_value,center):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface(brick_dimentions)
        self.image.fill(purple)
        self.rect = self.image.get_rect()
        self.rect.center = center
        self.point_value = point_value

    def takeHit( self,ball_sprite ): 
        # the ball has collided with *this* brick
        self.point_value -= 1
        if self.point_value == 0:
            self.kill() 

然后在Ball.collision()中使用pygame.sprite.spritecollide()来获取与球相撞的砖块列表,并降低其命中点:

class Ball:
    # [...]

    def collision(self):
        # calculate the list of bricks hit
        hit_list = pygame.sprite.spritecollide( self,brick_sprites,False )
        for brick in hit_list:
            brick.takeHit()     # may (or may not) kill the brick

在大多数情况下,hit_list将是单个积木,但根据球的大小,可能偶尔是两个积木。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。