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