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