在主屏幕以外的表面上进行 blitting 时奇怪的碰撞检测
weird collision detection when blitting on a surface other than the main screen
当我用鼠标点击发射导弹时它与其中一个方块发生碰撞,我希望移除方块和导弹。
但是,我想把形状放在透明的表面上以便于移动它,这就是问题所在,因为块没有被移除并且检测到碰撞很晚。
from math import *
import sys
import pygame
from pygame.locals import *
pygame.init()
fps = 60
fpsClock = pygame.time.Clock()
ADD_MISSILE = pygame.USEREVENT + 1
width, height = 1244, 740
screen = pygame.display.set_mode((width, height))
shape = [
' ************** ',
' ****** ****** ',
' **** **** ',
' ** ** ',
' ** ** ',
' **** **** ',
' ** ** ',
'**** ****',
'** **',
'** **',
'** **',
'** **',
'** **',
'**** ****',
' ** ** ',
' **** **** ',
' ** ** ',
' ** ** ',
' **** **** ',
' ****** ****** ',
' ************** ',
]
BLOCKSIZE = 8
class Block(pygame.sprite.Sprite):
def __init__(self, size, color, x, y):
super().__init__()
self.image = pygame.Surface((size, size))
self.image.fill(color)
self.rect = self.image.get_rect(topleft=(x, y))
class Missile(pygame.sprite.Sprite):
def __init__(self, pos):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((6, 2))
self.image.fill('red')
self.rect = self.image.get_rect(center=(pos))
self.vx = 4
def update(self):
self.rect.x -= self.vx
def setup_blocks():
for row_index, row in enumerate(shape):
for col_index, col in enumerate(row):
if col == '*':
x = BLOCKSIZE*col_index
y = BLOCKSIZE*row_index
blocks_sprite.add(Block(BLOCKSIZE,'red',x, y))
def collisions():
if pygame.sprite.groupcollide(blocks_sprite,missiles_sprite,True,True):
print("collision")
blocks_sprite = pygame.sprite.Group()
missiles_sprite = pygame.sprite.Group()
setup_blocks()
width = len(shape[0])
height = len(shape)
surf = pygame.Surface((width*BLOCKSIZE, height*BLOCKSIZE),SRCALPHA)
surf_rect = surf.get_rect()
#surf.fill('green')
while True:
screen.fill('white')
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
missiles_sprite.add(Missile(pygame.mouse.get_pos()))
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
surf_rect.x += 5
missiles_sprite.update()
missiles_sprite.draw(screen)
for block in blocks_sprite.sprites():
surf.blit(block.image,block.rect)
#screen.blit(block.image,block.rect)
screen.blit(surf,surf_rect)
collisions()
pygame.display.update()
fpsClock.tick(fps)
实际上块被删除了。但是,您必须清除绘制方块的 Surface:
while True:
# [...]
screen.fill('white')
missiles_sprite.draw(screen)
surf.fill((0, 0, 0, 0)) # <-- clear "surf"
for block in blocks_sprite.sprites():
surf.blit(block.image,block.rect)
screen.blit(surf,surf_rect)
pygame.display.update()
fpsClock.tick(fps)
无论如何,在单独的 Surface 上绘制块是个坏主意,因为这会破坏碰撞检测。在这种情况下,块的 rect
属性是相对于 surf
的。但是,pygame.sprite.groupcollide
仅在 rect
属性与屏幕相关时才有效。我建议改为移动积木。这是实现您自己的碰撞检测所需的更少代码:
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
missiles_sprite.add(Missile(pygame.mouse.get_pos()))
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
for block in blocks_sprite.sprites():
block.rect.x += 5
missiles_sprite.update()
collisions()
screen.fill('white')
blocks_sprite.draw(screen)
missiles_sprite.draw(screen)
pygame.display.update()
fpsClock.tick(fps)
或者你自己的碰撞控制可以是这样的:
def collisions(surf_rect):
for block in blocks_sprite:
blokc_rect = block.rect.move(surf_rect.x, surf_rect.y)
for missel in missiles_sprite:
if blokc_rect.colliderect(missel.rect):
block.kill()
missel.kill()
blocks_sprite = pygame.sprite.Group()
missiles_sprite = pygame.sprite.Group()
setup_blocks()
width = len(shape[0])
height = len(shape)
surf = pygame.Surface((width*BLOCKSIZE, height*BLOCKSIZE),SRCALPHA)
surf_rect = surf.get_rect()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
missiles_sprite.add(Missile(pygame.mouse.get_pos()))
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
surf_rect.x += 5
missiles_sprite.update()
collisions(surf_rect)
screen.fill('white')
missiles_sprite.draw(screen)
print(len(blocks_sprite.sprites()))
surf.fill((0, 0, 0, 0))
for block in blocks_sprite.sprites():
surf.blit(block.image,block.rect)
screen.blit(surf,surf_rect)
pygame.display.update()
fpsClock.tick(fps)
当我用鼠标点击发射导弹时它与其中一个方块发生碰撞,我希望移除方块和导弹。 但是,我想把形状放在透明的表面上以便于移动它,这就是问题所在,因为块没有被移除并且检测到碰撞很晚。
from math import *
import sys
import pygame
from pygame.locals import *
pygame.init()
fps = 60
fpsClock = pygame.time.Clock()
ADD_MISSILE = pygame.USEREVENT + 1
width, height = 1244, 740
screen = pygame.display.set_mode((width, height))
shape = [
' ************** ',
' ****** ****** ',
' **** **** ',
' ** ** ',
' ** ** ',
' **** **** ',
' ** ** ',
'**** ****',
'** **',
'** **',
'** **',
'** **',
'** **',
'**** ****',
' ** ** ',
' **** **** ',
' ** ** ',
' ** ** ',
' **** **** ',
' ****** ****** ',
' ************** ',
]
BLOCKSIZE = 8
class Block(pygame.sprite.Sprite):
def __init__(self, size, color, x, y):
super().__init__()
self.image = pygame.Surface((size, size))
self.image.fill(color)
self.rect = self.image.get_rect(topleft=(x, y))
class Missile(pygame.sprite.Sprite):
def __init__(self, pos):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((6, 2))
self.image.fill('red')
self.rect = self.image.get_rect(center=(pos))
self.vx = 4
def update(self):
self.rect.x -= self.vx
def setup_blocks():
for row_index, row in enumerate(shape):
for col_index, col in enumerate(row):
if col == '*':
x = BLOCKSIZE*col_index
y = BLOCKSIZE*row_index
blocks_sprite.add(Block(BLOCKSIZE,'red',x, y))
def collisions():
if pygame.sprite.groupcollide(blocks_sprite,missiles_sprite,True,True):
print("collision")
blocks_sprite = pygame.sprite.Group()
missiles_sprite = pygame.sprite.Group()
setup_blocks()
width = len(shape[0])
height = len(shape)
surf = pygame.Surface((width*BLOCKSIZE, height*BLOCKSIZE),SRCALPHA)
surf_rect = surf.get_rect()
#surf.fill('green')
while True:
screen.fill('white')
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
missiles_sprite.add(Missile(pygame.mouse.get_pos()))
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
surf_rect.x += 5
missiles_sprite.update()
missiles_sprite.draw(screen)
for block in blocks_sprite.sprites():
surf.blit(block.image,block.rect)
#screen.blit(block.image,block.rect)
screen.blit(surf,surf_rect)
collisions()
pygame.display.update()
fpsClock.tick(fps)
实际上块被删除了。但是,您必须清除绘制方块的 Surface:
while True:
# [...]
screen.fill('white')
missiles_sprite.draw(screen)
surf.fill((0, 0, 0, 0)) # <-- clear "surf"
for block in blocks_sprite.sprites():
surf.blit(block.image,block.rect)
screen.blit(surf,surf_rect)
pygame.display.update()
fpsClock.tick(fps)
无论如何,在单独的 Surface 上绘制块是个坏主意,因为这会破坏碰撞检测。在这种情况下,块的 rect
属性是相对于 surf
的。但是,pygame.sprite.groupcollide
仅在 rect
属性与屏幕相关时才有效。我建议改为移动积木。这是实现您自己的碰撞检测所需的更少代码:
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
missiles_sprite.add(Missile(pygame.mouse.get_pos()))
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
for block in blocks_sprite.sprites():
block.rect.x += 5
missiles_sprite.update()
collisions()
screen.fill('white')
blocks_sprite.draw(screen)
missiles_sprite.draw(screen)
pygame.display.update()
fpsClock.tick(fps)
或者你自己的碰撞控制可以是这样的:
def collisions(surf_rect):
for block in blocks_sprite:
blokc_rect = block.rect.move(surf_rect.x, surf_rect.y)
for missel in missiles_sprite:
if blokc_rect.colliderect(missel.rect):
block.kill()
missel.kill()
blocks_sprite = pygame.sprite.Group()
missiles_sprite = pygame.sprite.Group()
setup_blocks()
width = len(shape[0])
height = len(shape)
surf = pygame.Surface((width*BLOCKSIZE, height*BLOCKSIZE),SRCALPHA)
surf_rect = surf.get_rect()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
missiles_sprite.add(Missile(pygame.mouse.get_pos()))
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
surf_rect.x += 5
missiles_sprite.update()
collisions(surf_rect)
screen.fill('white')
missiles_sprite.draw(screen)
print(len(blocks_sprite.sprites()))
surf.fill((0, 0, 0, 0))
for block in blocks_sprite.sprites():
surf.blit(block.image,block.rect)
screen.blit(surf,surf_rect)
pygame.display.update()
fpsClock.tick(fps)