Shooting Bullets
Dodging is only half of Asteroids, next you'll give the ship a way to fight back.
A Bullet class
import math
import pygame
class Bullet:
def __init__(self, x, y, angle):
self.x = x
self.y = y
radians = math.radians(angle)
self.dx = -math.sin(radians) * 10
self.dy = math.cos(radians) * -10
self.life = 60 # frames until it disappears, about 1 second at 60 FPS
def update(self):
self.x += self.dx
self.y += self.dy
self.life -= 1
def is_dead(self):
return self.life <= 0
def draw(self, screen):
pygame.draw.circle(screen, (255, 220, 100), (int(self.x), int(self.y)), 3)
A bullet reuses the same angle-to-direction math as the ship's update, fired at a fixed speed (10) in whatever direction the ship was facing at the moment it fired. The life counter, decremented every frame, is what makes bullets disappear on their own instead of flying forever, is_dead() gives the rest of the code a clean way to ask "should this be removed yet?".
Firing on spacebar, with a cooldown
bullets = []
cooldown = 0
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE] and cooldown == 0:
bullets.append(Bullet(player.x, player.y, player.angle))
cooldown = 15 # frames before you can fire again
if cooldown > 0:
cooldown -= 1
for bullet in bullets:
bullet.update()
bullets = [b for b in bullets if not b.is_dead()]
# ... player and asteroid updates from earlier lessons ...
screen.fill((10, 10, 30))
for bullet in bullets:
bullet.draw(screen)
pygame.display.flip()
clock.tick(60)
Two details are doing the real work here:
- The cooldown counter stops holding spacebar from firing a new bullet every single frame (60 a second!), a fixed delay between shots is what makes it feel like a weapon instead of a hose.
- The list comprehension
[b for b in bullets if not b.is_dead()]rebuilds thebulletslist containing only the ones still alive, this is the standard Python idiom for "remove items matching a condition" from a list, since you can't safely remove items from a list while iterating over it directly.
TIP
This same "append when spawned, filter out when dead" pattern is exactly how you'll manage destroyed asteroids in the next lesson too, it's worth getting comfortable with here first.