Have Enemies Periodically Shoot

Having enemies shoot every x seconds is a bit more complex than shooting randomly as shown in Have Enemies Randomly Shoot. This is because we need to track how often we shoot, and how long it has been since we last shot.

This example uses custom sub-class EnemySprite. The extra attributes allow us to track the periodic timing. See the highlighted lines for what is specific to this example.

Screenshot of using sprites to shoot things
sprite_bullets_periodic.py
  1"""
  2Show how to have enemies shoot bullets at regular intervals.
  3
  4If Python and Arcade are installed, this example can be run from the command line with:
  5python -m arcade.examples.sprite_bullets_periodic
  6"""
  7import arcade
  8
  9SCREEN_WIDTH = 800
 10SCREEN_HEIGHT = 600
 11SCREEN_TITLE = "Sprites and Periodic Bullets Example"
 12
 13
 14class EnemySprite(arcade.Sprite):
 15    """ Enemy ship class that tracks how long it has been since firing. """
 16
 17    def __init__(self, image_file, scale, bullet_list, time_between_firing):
 18        """ Set up the enemy """
 19        super().__init__(image_file, scale)
 20
 21        # How long has it been since we last fired?
 22        self.time_since_last_firing = 0.0
 23
 24        # How often do we fire?
 25        self.time_between_firing = time_between_firing
 26
 27        # When we fire, what list tracks the bullets?
 28        self.bullet_list = bullet_list
 29
 30    def on_update(self, delta_time: float = 1/60):
 31        """ Update this sprite. """
 32
 33        # Track time since we last fired
 34        self.time_since_last_firing += delta_time
 35
 36        # If we are past the firing time, then fire
 37        if self.time_since_last_firing >= self.time_between_firing:
 38
 39            # Reset timer
 40            self.time_since_last_firing = 0
 41
 42            # Fire the bullet
 43            bullet = arcade.Sprite(":resources:images/space_shooter/laserBlue01.png")
 44            bullet.center_x = self.center_x
 45            bullet.angle = -90
 46            bullet.top = self.bottom
 47            bullet.change_y = -2
 48            self.bullet_list.append(bullet)
 49
 50
 51class MyGame(arcade.Window):
 52    """ Main application class """
 53
 54    def __init__(self):
 55        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
 56
 57        arcade.set_background_color(arcade.color.BLACK)
 58
 59        self.player = None
 60        self.player_list = None
 61        self.enemy_list = None
 62        self.bullet_list = None
 63
 64    def setup(self):
 65        """ Setup the variables for the game. """
 66
 67        self.player_list = arcade.SpriteList()
 68        self.enemy_list = arcade.SpriteList()
 69        self.bullet_list = arcade.SpriteList()
 70
 71        # Add player ship
 72        self.player = arcade.Sprite(":resources:images/space_shooter/playerShip1_orange.png", 0.5)
 73        self.player_list.append(self.player)
 74
 75        # Add top-left enemy ship
 76        enemy = EnemySprite(":resources:images/space_shooter/playerShip1_green.png",
 77                            scale=0.5,
 78                            bullet_list=self.bullet_list,
 79                            time_between_firing=2.0)
 80        enemy.center_x = 120
 81        enemy.center_y = SCREEN_HEIGHT - enemy.height
 82        enemy.angle = 180
 83        self.enemy_list.append(enemy)
 84
 85        # Add top-right enemy ship
 86        enemy = EnemySprite(":resources:images/space_shooter/playerShip1_green.png",
 87                            scale=0.5,
 88                            bullet_list=self.bullet_list,
 89                            time_between_firing=1.0)
 90        enemy.center_x = SCREEN_WIDTH - 120
 91        enemy.center_y = SCREEN_HEIGHT - enemy.height
 92        enemy.angle = 180
 93        self.enemy_list.append(enemy)
 94
 95    def on_draw(self):
 96        """Render the screen. """
 97
 98        arcade.start_render()
 99
100        self.enemy_list.draw()
101        self.bullet_list.draw()
102        self.player_list.draw()
103
104    def on_update(self, delta_time):
105        """ All the logic to move, and the game logic goes here. """
106
107        # Call on_update for each enemy in  the list
108        self.enemy_list.on_update(delta_time)
109
110        # Get rid of the bullet when it flies off-screen
111        for bullet in self.bullet_list:
112            if bullet.top < 0:
113                bullet.remove_from_sprite_lists()
114
115        self.bullet_list.update()
116
117    def on_mouse_motion(self, x, y, delta_x, delta_y):
118        """
119        Called whenever the mouse moves.
120        """
121        self.player.center_x = x
122        self.player.center_y = 20
123
124
125def main():
126    """ Run the game """
127    window = MyGame()
128    window.setup()
129    arcade.run()
130
131
132if __name__ == "__main__":
133    main()