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
 18SCREEN_WIDTH = 800
 19SCREEN_HEIGHT = 600
 20SCREEN_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):
 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 > SCREEN_WIDTH - 1:
 45            self.right = SCREEN_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 > SCREEN_HEIGHT - 1:
 52            self.top = SCREEN_HEIGHT - 1
 53            self.change_y = 0
 54
 55
 56class MyGame(arcade.Window):
 57    """
 58    Main application class.
 59    """
 60
 61    def __init__(self, width, height, title):
 62        """
 63        Initializer
 64        """
 65
 66        # Call the parent class initializer
 67        super().__init__(width, height, title)
 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(":resources:images/animated_characters/female_person/femalePerson_idle.png",
 97                                    scale=SPRITE_SCALING)
 98        self.player_sprite.position = self.width / 2, self.height / 2
 99        self.player_list.append(self.player_sprite)
100
101        # Create the speed display objects with initial text
102        self.x_speed_display = arcade.Text(
103            f"X Speed: {self.player_sprite.change_x:6.3f}",
104            10, 50, arcade.color.BLACK)
105
106        self.y_speed_display = arcade.Text(
107            f"Y Speed: {self.player_sprite.change_y:6.3f}",
108            10, 70, arcade.color.BLACK)
109
110    def on_draw(self):
111        """
112        Render the screen.
113        """
114
115        # This command has to happen before we start drawing
116        self.clear()
117
118        # Draw all the sprites.
119        self.player_list.draw()
120
121        # Draw the speed indicators
122        self.x_speed_display.draw()
123        self.y_speed_display.draw()
124
125    def on_update(self, delta_time):
126        """ Movement and game logic """
127
128        # Add some friction
129        if self.player_sprite.change_x > FRICTION:
130            self.player_sprite.change_x -= FRICTION
131        elif self.player_sprite.change_x < -FRICTION:
132            self.player_sprite.change_x += FRICTION
133        else:
134            self.player_sprite.change_x = 0
135
136        if self.player_sprite.change_y > FRICTION:
137            self.player_sprite.change_y -= FRICTION
138        elif self.player_sprite.change_y < -FRICTION:
139            self.player_sprite.change_y += FRICTION
140        else:
141            self.player_sprite.change_y = 0
142
143        # Apply acceleration based on the keys pressed
144        if self.up_pressed and not self.down_pressed:
145            self.player_sprite.change_y += ACCELERATION_RATE
146        elif self.down_pressed and not self.up_pressed:
147            self.player_sprite.change_y += -ACCELERATION_RATE
148        if self.left_pressed and not self.right_pressed:
149            self.player_sprite.change_x += -ACCELERATION_RATE
150        elif self.right_pressed and not self.left_pressed:
151            self.player_sprite.change_x += ACCELERATION_RATE
152
153        if self.player_sprite.change_x > MAX_SPEED:
154            self.player_sprite.change_x = MAX_SPEED
155        elif self.player_sprite.change_x < -MAX_SPEED:
156            self.player_sprite.change_x = -MAX_SPEED
157        if self.player_sprite.change_y > MAX_SPEED:
158            self.player_sprite.change_y = MAX_SPEED
159        elif self.player_sprite.change_y < -MAX_SPEED:
160            self.player_sprite.change_y = -MAX_SPEED
161
162        # Call update to move the sprite
163        # IMPORTANT: If using a physics engine, you need to call update
164        # on it instead of the sprite list!
165        self.player_list.update()
166
167        # Update the speed displays based on the final speed
168        self.x_speed_display.text = f"X Speed: {self.player_sprite.change_x:6.3f}"
169        self.y_speed_display.text = f"Y Speed: {self.player_sprite.change_y:6.3f}"
170
171    def on_key_press(self, key, modifiers):
172        """Called whenever a key is pressed. """
173
174        if key == arcade.key.UP:
175            self.up_pressed = True
176        elif key == arcade.key.DOWN:
177            self.down_pressed = True
178        elif key == arcade.key.LEFT:
179            self.left_pressed = True
180        elif key == arcade.key.RIGHT:
181            self.right_pressed = True
182
183    def on_key_release(self, key, modifiers):
184        """Called when the user releases a key. """
185
186        if key == arcade.key.UP:
187            self.up_pressed = False
188        elif key == arcade.key.DOWN:
189            self.down_pressed = False
190        elif key == arcade.key.LEFT:
191            self.left_pressed = False
192        elif key == arcade.key.RIGHT:
193            self.right_pressed = False
194
195
196def main():
197    """ Main function """
198    window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
199    window.setup()
200    arcade.run()
201
202
203if __name__ == "__main__":
204    main()