这是一个示例,其中我存储了对播放器内部两个子弹组的引用。如果您按下开火键('f' 或空格),则会将一个子弹实例添加到玩家的子弹组和 all_sprites 组中,该组会闪烁并更新它们。
碰撞检测发生在update 方法中,我检查玩家是否与self.enemy_bullets 组的子弹发生碰撞。如果有冲突,我会减少self.health,如果是<= 0,我会调用self.kill() 从所有精灵组中删除精灵。
import pygame as pg
from pygame.math import Vector2
class Player(pg.sprite.Sprite):
def __init__(self, pos, color, left, right, up, down, fire,
all_sprites, bullets, enemy_bullets):
super().__init__()
self.image = pg.Surface((30, 50))
self.image.fill(color)
self.rect = self.image.get_rect(topleft=pos)
self.vel = Vector2(0, 0)
self.pos = Vector2(self.rect.topleft)
self.dt = 0.03
self.key_left = left
self.key_right = right
self.key_up = up
self.key_down = down
self.key_fire = fire
# Store the groups as attributes, so that you can add bullets
# and use them for the collision detection in the update method.
self.all_sprites = all_sprites
self.bullets = bullets
self.enemy_bullets = enemy_bullets
self.fire_direction = Vector2(350, 0)
self.health = 3
def update(self, dt):
self.dt = dt
self.pos += self.vel
self.rect.center = self.pos
# Check if enemy bullets collide with the player, reduce
# health and kill self if health is <= 0.
collided_bullets = pg.sprite.spritecollide(self, self.enemy_bullets, True)
for bullet in collided_bullets:
self.health -= 1
if self.health <= 0:
self.kill()
def handle_event(self, event):
if event.type == pg.KEYDOWN:
if event.key == self.key_left:
self.vel.x = -90 * self.dt
self.fire_direction = Vector2(-350, 0)
elif event.key == self.key_right:
self.vel.x = 90 * self.dt
self.fire_direction = Vector2(350, 0)
elif event.key == self.key_up:
self.vel.y = -90 * self.dt
self.fire_direction = Vector2(0, -350)
elif event.key == self.key_down:
self.vel.y = 90 * self.dt
self.fire_direction = Vector2(0, 350)
elif event.key == self.key_fire: # Add a bullet to the groups.
bullet = Bullet(self.rect.center, self.fire_direction)
self.bullets.add(bullet)
self.all_sprites.add(bullet)
elif event.type == pg.KEYUP:
if event.key == self.key_left and self.vel.x < 0:
self.vel.x = 0
elif event.key == self.key_right and self.vel.x > 0:
self.vel.x = 0
elif event.key == self.key_up and self.vel.y < 0:
self.vel.y = 0
elif event.key == self.key_down and self.vel.y > 0:
self.vel.y = 0
class Bullet(pg.sprite.Sprite):
def __init__(self, pos, velocity):
super().__init__()
self.image = pg.Surface((5, 5))
self.image.fill(pg.Color('aquamarine1'))
self.rect = self.image.get_rect(center=pos)
self.pos = pos
self.vel = velocity
def update(self, dt):
self.pos += self.vel * dt
self.rect.center = self.pos
class Game:
def __init__(self):
self.fps = 30
self.done = False
self.clock = pg.time.Clock()
self.screen = pg.display.set_mode((800, 600))
self.bg_color = pg.Color('gray30')
# Sprite groups that contain the players and bullets.
self.all_sprites = pg.sprite.Group()
self.bullets1 = pg.sprite.Group() # Will contain bullets of player1.
self.bullets2 = pg.sprite.Group() # Will contain bullets of player2.
player1 = Player(
(100, 300), pg.Color('dodgerblue2'),
pg.K_a, pg.K_d, pg.K_w, pg.K_s, pg.K_f,
self.all_sprites, self.bullets1, self.bullets2) # Pass the groups.
player2 = Player(
(300, 400), pg.Color('sienna2'),
pg.K_j, pg.K_l, pg.K_i, pg.K_k, pg.K_SPACE,
self.all_sprites, self.bullets2, self.bullets1) # Pass the groups.
self.all_sprites.add(player1, player2)
self.players = pg.sprite.Group(player1, player2)
def run(self):
while not self.done:
self.dt = self.clock.tick(self.fps) / 1000
self.handle_events()
self.run_logic()
self.draw()
def handle_events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
for player in self.players:
player.handle_event(event)
def run_logic(self):
self.all_sprites.update(self.dt)
def draw(self):
self.screen.fill(self.bg_color)
self.all_sprites.draw(self.screen)
pg.display.flip()
if __name__ == '__main__':
pg.init()
Game().run()
pg.quit()
如果您想直接在事件循环中进行事件处理,可以将Player 的handle_event 方法中的代码移动到Game 的handle_event 方法中。这是一个简短的示例:
import pygame as pg
from pygame.math import Vector2
class Player(pg.sprite.Sprite):
def __init__(self, pos, *groups):
super().__init__(*groups)
self.image = pg.Surface((30, 50))
self.image.fill(pg.Color('steelblue2'))
self.rect = self.image.get_rect(center=pos)
self.vel = Vector2(0, 0)
self.pos = Vector2(pos)
def update(self):
self.pos += self.vel
self.rect.center = self.pos
class Bullet(pg.sprite.Sprite):
def __init__(self, pos, velocity):
super().__init__()
self.image = pg.Surface((5, 5))
self.image.fill(pg.Color('aquamarine1'))
self.rect = self.image.get_rect(center=pos)
self.pos = pos
self.vel = velocity
def update(self):
self.pos += self.vel
self.rect.center = self.pos
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
bullets = pg.sprite.Group()
player = Player((100, 300), all_sprites)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_d:
player.vel.x = 5
elif event.key == pg.K_SPACE:
# Just create a bullet and add it to the sprite groups.
bullet = Bullet(player.rect.center, Vector2(8, 0))
bullets.add(bullet)
all_sprites.add(bullet)
elif event.type == pg.KEYUP:
if event.key == pg.K_d:
player.vel.x = 0
all_sprites.update()
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()