Python (pygame) 碰撞检测 - 精灵与组
我刚开始学Python,正在尝试写一个游戏。在这个游戏里,角色会被发射出去,当他和地面上的一个精灵互动时,会发生一些变化,比如速度会改变。抱歉我的代码有点乱。我从几个教程中拿了一些示例,但我无法把它们结合在一起。
我该如何检测玩家和炸弹的碰撞呢?
import pygame
import random
import math
drag = 1
gravity = (math.pi, .4)
elasticity = .75
# Colors
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
BLUE = ( 0, 0, 255)
RED = ( 255, 0, 0)
GREEN = ( 0, 255, 0)
# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
def addVectors((angle1, length1), (angle2, length2)):
x = math.sin(angle1) * length1 + math.sin(angle2) * length2
y = math.cos(angle1) * length1 + math.cos(angle2) * length2
angle = 0.5 * math.pi - math.atan2(y, x)
length = math.hypot(x, y)
return (angle, length)
class Player(pygame.sprite.Sprite):
change_x = 0
change_y = 0
level = None
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('player.png')
image_rect = self.image.get_rect()
self.rect = pygame.rect.Rect(x, y, image_rect.width, image_rect.height)
def update(self):
pass
def move(self):
(self.angle, self.speed) = addVectors((self.angle, self.speed), gravity)
self.rect.x += math.sin(self.angle) * self.speed
self.rect.y -= math.cos(self.angle) * self.speed
self.speed *= drag
def bounce(self):
if self.rect.x > 800 - self.rect.width:
self.rect.x = 2*(800 - self.rect.width) - self.rect.x
self.angle = - self.angle
self.speed *= elasticity
elif self.rect.x < 0:
self.rect.x = 2*self.rect.width - self.rect.x
self.angle = - self.angle
self.speed *= elasticity
if self.rect.y > SCREEN_HEIGHT - self.rect.height:
self.rect.y = 2*(SCREEN_HEIGHT - self.rect.height) - self.rect.y
self.angle = math.pi - self.angle
self.speed *= elasticity
class Bomb(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('cherry.png')
image_rect = self.image.get_rect()
self.rect = pygame.rect.Rect(x, y, image_rect.width, image_rect.height)
class Level():
bomb_list = None
world_shift = 0
def __init__(self, player):
self.bomb_list = pygame.sprite.Group()
self.player = player
def update(self):
self.bomb_list.update()
def draw(self, screen):
screen.fill(BLACK)
self.bomb_list.draw(screen)
def shift_world(self, shift_x):
self.world_shift += shift_x
for bomb in self.bomb_list:
bomb.rect.x += shift_x
if bomb.rect.x < 0:
self.bomb_list.remove(bomb)
self.bomb_list.add(Bomb(random.randint(SCREEN_WIDTH, 2*SCREEN_WIDTH), 580))
我不确定这个Level_01类是否真的有必要:
class Level_01(Level):
def __init__(self, player):
Level.__init__(self, player)
bombs = 0
for n in range(10):
self.bomb_list.add(Bomb(random.randint(0, SCREEN_WIDTH), 580))
这是我尝试写的碰撞检测方法。我不确定这个方法应该放在一个类里、主程序里,还是单独放。我似乎无法同时获取炸弹的列表和玩家的信息。
def detectCollisions(sprite1, sprite_group):
if pygame.sprite.spritecollideany(sprite1, sprite_group):
sprite_group.remove(pygame.sprite.spritecollideany(sprite1, sprite_group))
print True
else:
print False
def main():
pygame.init()
size = [SCREEN_WIDTH, SCREEN_HEIGHT]
screen = pygame.display.set_mode(size)
active_sprite_list = pygame.sprite.Group()
enemy_list = pygame.sprite.Group()
player = Player(0, 0)
player.speed = 30
player.angle = math.radians(45)
player.rect.x = 500
player.rect.y = SCREEN_HEIGHT - player.rect.height
active_sprite_list.add(player)
done = False
clock = pygame.time.Clock()
current_level = Level_01(player)
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.go_left()
if event.key == pygame.K_RIGHT:
player.go_right()
active_sprite_list.update()
enemy_list.update()
player.level = current_level
player.move()
player.bounce()
if player.rect.x >= 500:
diff = player.rect.x - 500
player.rect.x = 500
current_level.shift_world(-diff)
if player.rect.x <= 120:
diff = 120 - player.rect.x
player.rect.x = 120
current_level.shift_world(diff)
current_level.draw(screen)
active_sprite_list.draw(screen)
enemy_list.draw(screen)
clock.tick(60)
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
谢谢你们的帮助!
2 个回答
0
我建议为每个类创建精灵组,使用 pygame.sprite.Group()
,比如 Bomb
(炸弹)和 Player
(玩家)。然后,可以使用 pygame.sprite.spritecollide()
来检测碰撞。
举个例子:
def Main()
...
player_list = pygame.sprite.Group()
bomb_list = pygame.sprite.Group()
...
然后在你的逻辑处理循环中,创建一个 Player
和 Bomb
实例后,你可以这样做:
for bomb in bomb_list:
# See if the bombs has collided with the player.
bomb_hit_list = pygame.sprite.spritecollide(bomb, player_list, True)
# For each bomb hit, remove bomb
for bomb in bomb_hit_list:
bomb_list.remove(bomb)
# --- Put code here that will trigger with each collision ---
0
最简单的方法就是画出像素(或者虚拟像素),如果在画炸弹或人物的像素时发现它们重叠了,那就说明发生了碰撞。
不过,如果你需要更高效的碰撞检测方法,可以让这个过程变得更复杂。可以参考维基百科上的碰撞检测内容。