python - Python pygame sprites 碰撞检测。如何定义哪个精灵与组碰撞并通过减少一个点来影响它的属性
问题描述
我想做的是创建一个打砖块游戏,其中每个砖块有 3 点强度,然后它们就会死亡。问题在于,不仅仅是被击中的特定砖块失去积分,整个brick_sprite 组正在失去积分。并且当一个人假设死亡时,列表中的所有之前的人都会死亡。我认为问题在于考虑到第 240 行的更新,它会循环。def collision(self):
请在Brick
Class下方查看第 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, 0)
orange = (255, 100, 10)
light_blue = (0, 144, 255)
shadow = (192, 192, 192)
purple = (152, 0, 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, loses a point
collision = pygame.sprite.spritecollide(ball, brick_sprites, 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, 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
班级中,称碰撞。
sprite update 函数通常用于更改 sprite 的位置或外观,每帧调用一次。所以这不是检查碰撞的好地方。
ABrick
只需要知道它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
将是一块砖,但根据球的大小,有时可能是两块砖。
推荐阅读
- templates - 使用 Deployment Manager 模板配置防火墙和启动脚本时出现问题
- flutter - 如何在 tabBarView 中有状态小部件?
- angular - 页面上多次使用组件时如何从父组件发回数据
- sql - 如何减少存储过程的执行时间?
- javascript - 通过与第一列进行比较来更改第二列的颜色
- ios - 将 JSON 转换为对象时,AlamofireObjectMapper 崩溃
- angular - 如何为 Angular 配置视口插件
- angular - 同步可观测角度
- java - 如何在多模块 Gradle 项目中构建分发包?
- javascript - 如何根据下拉选择代码点火器刷新值