Sprites That Follow a Path

Screen shot of a sprite following a path
follow_path.py
  1"""
  2Sprite Follow Path
  3
  4This example has enemy sprites follow a set path.
  5
  6Artwork from https://kenney.nl
  7
  8If Python and Arcade are installed, this example can be run from the command line with:
  9python -m arcade.examples.follow_path
 10"""
 11
 12import arcade
 13import math
 14
 15# --- Constants ---
 16SPRITE_SCALING_PLAYER = 0.5
 17SPRITE_SCALING_ENEMY = 0.5
 18ENEMY_SPEED = 5.0
 19
 20WINDOW_WIDTH = 1289
 21WINDOW_HEIGHT = 720
 22WINDOW_TITLE = "Sprite Follow Path Simple Example"
 23
 24
 25class Enemy(arcade.Sprite):
 26    """
 27    This class represents the Enemy on our screen.
 28    """
 29
 30    def __init__(self, image, scale, position_list):
 31        super().__init__(image, scale=scale)
 32        self.position_list = position_list
 33        self.cur_position = 0
 34        self.speed = ENEMY_SPEED
 35
 36    def update(self, delta_time: float = 1 / 60):
 37        """Have a sprite follow a path"""
 38        # Where are we
 39        start_x = self.center_x
 40        start_y = self.center_y
 41
 42        # Where are we going
 43        dest_x = self.position_list[self.cur_position][0]
 44        dest_y = self.position_list[self.cur_position][1]
 45
 46        # X and Y diff between the two
 47        x_diff = dest_x - start_x
 48        y_diff = dest_y - start_y
 49
 50        # Calculate angle to get there
 51        angle = math.atan2(y_diff, x_diff)
 52
 53        # How far are we?
 54        distance = math.sqrt((self.center_x - dest_x) ** 2 + (self.center_y - dest_y) ** 2)
 55
 56        # How fast should we go? If we are close to our destination,
 57        # lower our speed so we don't overshoot.
 58        speed = min(self.speed, distance)
 59
 60        # Calculate vector to travel
 61        change_x = math.cos(angle) * speed
 62        change_y = math.sin(angle) * speed
 63
 64        # Update our location
 65        self.center_x += change_x
 66        self.center_y += change_y
 67
 68        # How far are we?
 69        distance = math.sqrt((self.center_x - dest_x) ** 2 + (self.center_y - dest_y) ** 2)
 70
 71        # If we are there, head to the next point.
 72        if distance <= self.speed:
 73            self.cur_position += 1
 74
 75            # Reached the end of the list, start over.
 76            if self.cur_position >= len(self.position_list):
 77                self.cur_position = 0
 78
 79
 80class GameView(arcade.View):
 81
 82    def __init__(self):
 83        """ Initializer """
 84        # Call the parent class initializer
 85        super().__init__()
 86
 87        # Variables that will hold sprite lists
 88        self.player_list = None
 89        self.enemy_list = None
 90
 91        # Set up the player info
 92        self.player_sprite = None
 93        self.score = 0
 94
 95        # Don't show the mouse cursor
 96        self.window.set_mouse_visible(False)
 97
 98        self.background_color = arcade.color.AMAZON
 99
100    def setup(self):
101        """ Set up the game and initialize the variables. """
102
103        # Sprite lists
104        self.player_list = arcade.SpriteList()
105        self.enemy_list = arcade.SpriteList()
106
107        # Score
108        self.score = 0
109
110        # Set up the player
111        # Character image from kenney.nl
112        self.player_sprite = arcade.Sprite(
113            ":resources:images/animated_characters/female_person/femalePerson_idle.png",
114            scale=SPRITE_SCALING_PLAYER)
115        self.player_sprite.center_x = 50
116        self.player_sprite.center_y = 50
117        self.player_list.append(self.player_sprite)
118
119        # List of points the enemy will travel too.
120        position_list = [
121            [50, 50],
122            [self.width - 50, 50],
123            [self.width - 50, self.height - 50],
124            [50, self.height - 50],
125        ]
126        # Spawn a few enemies
127        self.spawn_enemy((50, 50), position_list)
128        self.spawn_enemy((50, 250), position_list)
129        self.spawn_enemy((50, 450), position_list)
130        self.spawn_enemy((50, 650), position_list)
131
132    def spawn_enemy(self, position, position_list):
133        # Spawn a new enemy
134        enemy = Enemy(":resources:images/animated_characters/robot/robot_idle.png",
135                      SPRITE_SCALING_ENEMY,
136                      position_list)
137        # Set initial location of the enemy at the first point
138        enemy.position = position
139        self.enemy_list.append(enemy)
140
141    def on_draw(self):
142        """ Draw everything """
143        self.clear()
144        self.enemy_list.draw()
145        self.player_list.draw()
146
147    def on_mouse_motion(self, x, y, dx, dy):
148        """ Handle Mouse Motion """
149        # Move the center of the player sprite to match the mouse x, y
150        self.player_sprite.center_x = x
151        self.player_sprite.center_y = y
152
153    def on_update(self, delta_time):
154        """ Movement and game logic """
155        self.enemy_list.update()
156
157    def on_key_press(self, symbol: int, modifiers: int):
158        if symbol == arcade.key.ESCAPE:
159            self.window.close()
160
161
162def main():
163    """ Main function """
164    # Create a window class. This is what actually shows up on screen
165    window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
166
167    # Create and setup the GameView
168    game = GameView()
169    game.setup()
170
171    # Show GameView on screen
172    window.show_view(game)
173
174    # Start the arcade game loop
175    arcade.run()
176
177
178if __name__ == "__main__":
179    main()