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
  9WINDOW_WIDTH = 1280
 10WINDOW_HEIGHT = 720
 11WINDOW_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=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 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 GameView(arcade.View):
 52    """ Main application class """
 53
 54    def __init__(self):
 55        super().__init__()
 56
 57        self.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        """ Set up 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(
 73            ":resources:images/space_shooter/playerShip1_orange.png",
 74            scale=0.5,
 75        )
 76        self.player_list.append(self.player)
 77
 78        # Add top-left enemy ship
 79        enemy = EnemySprite(
 80            ":resources:images/space_shooter/playerShip1_green.png",
 81            scale=0.5,
 82            bullet_list=self.bullet_list,
 83            time_between_firing=2.0,
 84        )
 85        enemy.center_x = 120
 86        enemy.center_y = WINDOW_HEIGHT - enemy.height
 87        enemy.angle = 180
 88        self.enemy_list.append(enemy)
 89
 90        # Add top-right enemy ship
 91        enemy = EnemySprite(":resources:images/space_shooter/playerShip1_green.png",
 92                            scale=0.5,
 93                            bullet_list=self.bullet_list,
 94                            time_between_firing=1.0)
 95        enemy.center_x = WINDOW_WIDTH - 120
 96        enemy.center_y = WINDOW_HEIGHT - enemy.height
 97        enemy.angle = 180
 98        self.enemy_list.append(enemy)
 99
100    def on_draw(self):
101        """Render the screen. """
102
103        self.clear()
104
105        self.enemy_list.draw()
106        self.bullet_list.draw()
107        self.player_list.draw()
108
109    def on_update(self, delta_time):
110        """ All the logic to move, and the game logic goes here. """
111
112        # Call on_update for each enemy in  the list
113        self.enemy_list.update(delta_time)
114
115        # Get rid of the bullet when it flies off-screen
116        for bullet in self.bullet_list:
117            if bullet.top < 0:
118                bullet.remove_from_sprite_lists()
119
120        self.bullet_list.update(delta_time)
121
122    def on_mouse_motion(self, x, y, delta_x, delta_y):
123        """
124        Called whenever the mouse moves.
125        """
126        self.player.center_x = x
127        self.player.center_y = 20
128
129
130def main():
131    """ Main function """
132    # Create a window class. This is what actually shows up on screen
133    window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
134
135    # Create and setup the GameView
136    game = GameView()
137    game.setup()
138
139    # Show GameView on screen
140    window.show_view(game)
141
142    # Start the arcade game loop
143    arcade.run()
144
145
146if __name__ == "__main__":
147    main()