Acceleration and Friction

Screen shot of moving a sprite by keyboard
sprite_move_keyboard_accel.py
  1"""
  2Acceleration and Friction
  3
  4Demonstrate how to implement simple acceleration and friction without a
  5physics engine.
  6
  7Artwork from https://kenney.nl
  8
  9If Python and Arcade are installed, this example can be run from the
 10command line with:
 11python -m arcade.examples.sprite_move_keyboard_accel
 12"""
 13
 14import arcade
 15
 16SPRITE_SCALING = 0.5
 17
 18WINDOW_WIDTH = 1280
 19WINDOW_HEIGHT = 720
 20WINDOW_TITLE = "Better Move Sprite with Keyboard Example"
 21
 22# Important constants for this example
 23
 24# Speed limit
 25MAX_SPEED = 3.0
 26
 27# How fast we accelerate
 28ACCELERATION_RATE = 0.1
 29
 30# How fast to slow down after we let off the key
 31FRICTION = 0.02
 32
 33
 34class Player(arcade.Sprite):
 35
 36    def update(self, delta_time: float = 1/60):
 37        self.center_x += self.change_x
 38        self.center_y += self.change_y
 39
 40        # Check to see if we hit the screen edge
 41        if self.left < 0:
 42            self.left = 0
 43            self.change_x = 0  # Zero x speed
 44        elif self.right > WINDOW_WIDTH - 1:
 45            self.right = WINDOW_WIDTH - 1
 46            self.change_x = 0
 47
 48        if self.bottom < 0:
 49            self.bottom = 0
 50            self.change_y = 0
 51        elif self.top > WINDOW_HEIGHT - 1:
 52            self.top = WINDOW_HEIGHT - 1
 53            self.change_y = 0
 54
 55
 56class GameView(arcade.View):
 57    """
 58    Main application class.
 59    """
 60
 61    def __init__(self):
 62        """
 63        Initializer
 64        """
 65
 66        # Call the parent class initializer
 67        super().__init__()
 68
 69        # Variable to will hold the player sprite list
 70        self.player_list = None
 71
 72        # Create a place to store the player sprite
 73        # so it can be  accessed directly.
 74        self.player_sprite = None
 75
 76        # Create places to store the speed display Text objects
 77        self.x_speed_display = None
 78        self.y_speed_display = None
 79
 80        # Track the current state of what key is pressed
 81        self.left_pressed = False
 82        self.right_pressed = False
 83        self.up_pressed = False
 84        self.down_pressed = False
 85
 86        # Set the background color
 87        self.background_color = arcade.color.AMAZON
 88
 89    def setup(self):
 90        """ Set up the game and initialize the variables. """
 91
 92        # Create a sprite list
 93        self.player_list = arcade.SpriteList()
 94
 95        # Set up the player
 96        self.player_sprite = Player(
 97            ":resources:images/animated_characters/female_person/femalePerson_idle.png",
 98            scale=SPRITE_SCALING,
 99        )
100        self.player_sprite.position = self.width / 2, self.height / 2
101        self.player_list.append(self.player_sprite)
102
103        # Create the speed display objects with initial text
104        self.x_speed_display = arcade.Text(
105            f"X Speed: {self.player_sprite.change_x:6.3f}",
106            10, 50, arcade.color.BLACK, font_size=15,
107        )
108
109        self.y_speed_display = arcade.Text(
110            f"Y Speed: {self.player_sprite.change_y:6.3f}",
111            10, 70, color=arcade.color.BLACK, font_size=15,
112        )
113
114    def on_draw(self):
115        """
116        Render the screen.
117        """
118
119        # This command has to happen before we start drawing
120        self.clear()
121
122        # Draw all the sprites.
123        self.player_list.draw()
124
125        # Draw the speed indicators
126        self.x_speed_display.draw()
127        self.y_speed_display.draw()
128
129    def on_update(self, delta_time):
130        """ Movement and game logic """
131
132        # Add some friction
133        if self.player_sprite.change_x > FRICTION:
134            self.player_sprite.change_x -= FRICTION
135        elif self.player_sprite.change_x < -FRICTION:
136            self.player_sprite.change_x += FRICTION
137        else:
138            self.player_sprite.change_x = 0
139
140        if self.player_sprite.change_y > FRICTION:
141            self.player_sprite.change_y -= FRICTION
142        elif self.player_sprite.change_y < -FRICTION:
143            self.player_sprite.change_y += FRICTION
144        else:
145            self.player_sprite.change_y = 0
146
147        # Apply acceleration based on the keys pressed
148        if self.up_pressed and not self.down_pressed:
149            self.player_sprite.change_y += ACCELERATION_RATE
150        elif self.down_pressed and not self.up_pressed:
151            self.player_sprite.change_y += -ACCELERATION_RATE
152        if self.left_pressed and not self.right_pressed:
153            self.player_sprite.change_x += -ACCELERATION_RATE
154        elif self.right_pressed and not self.left_pressed:
155            self.player_sprite.change_x += ACCELERATION_RATE
156
157        if self.player_sprite.change_x > MAX_SPEED:
158            self.player_sprite.change_x = MAX_SPEED
159        elif self.player_sprite.change_x < -MAX_SPEED:
160            self.player_sprite.change_x = -MAX_SPEED
161        if self.player_sprite.change_y > MAX_SPEED:
162            self.player_sprite.change_y = MAX_SPEED
163        elif self.player_sprite.change_y < -MAX_SPEED:
164            self.player_sprite.change_y = -MAX_SPEED
165
166        # Call update to move the sprite
167        # IMPORTANT: If using a physics engine, you need to call update
168        # on it instead of the sprite list!
169        self.player_list.update(delta_time)
170
171        # Update the speed displays based on the final speed
172        self.x_speed_display.text = f"X Speed: {self.player_sprite.change_x:6.3f}"
173        self.y_speed_display.text = f"Y Speed: {self.player_sprite.change_y:6.3f}"
174
175    def on_key_press(self, key, modifiers):
176        """Called whenever a key is pressed. """
177
178        if key == arcade.key.UP:
179            self.up_pressed = True
180        elif key == arcade.key.DOWN:
181            self.down_pressed = True
182        elif key == arcade.key.LEFT:
183            self.left_pressed = True
184        elif key == arcade.key.RIGHT:
185            self.right_pressed = True
186
187    def on_key_release(self, key, modifiers):
188        """Called when the user releases a key. """
189
190        if key == arcade.key.UP:
191            self.up_pressed = False
192        elif key == arcade.key.DOWN:
193            self.down_pressed = False
194        elif key == arcade.key.LEFT:
195            self.left_pressed = False
196        elif key == arcade.key.RIGHT:
197            self.right_pressed = False
198
199
200def main():
201    """ Main function """
202    # Create a window class. This is what actually shows up on screen
203    window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
204
205    # Create and setup the GameView
206    game = GameView()
207    game.setup()
208
209    # Show GameView on screen
210    window.show_view(game)
211
212    # Start the arcade game loop
213    arcade.run()
214
215
216if __name__ == "__main__":
217    main()