Step 5 - Add Gravity#

The previous example great for top-down, but what if it is a side view with jumping like our platformer? We need to add gravity. First, let’s define a constant to represent the acceleration for gravity, and one for a jump speed.

05_add_gravity.py - Add Gravity#
# Movement speed of player, in pixels per frame
PLAYER_MOVEMENT_SPEED = 5

At the end of the setup method, change the physics engine to PhysicsEnginePlatformer and include gravity as a parameter.

05_add_gravity.py - Add Gravity#
            self.scene.add_sprite("Walls", wall)

        # Create the 'physics engine'
        self.physics_engine = arcade.PhysicsEnginePlatformer(

We are sending our SpriteList for the things the player should collide with to the walls parameter of the the physics engine. As we’ll see in later chapters, the platformer physics engine has a platforms and walls parameter. The difference between these is very important. Static non-moving spritelists should always be sent to the walls parameter, and moving sprites should be sent to the platforms parameter. Ensuring you do this will have extreme benefits to performance.

Adding static sprites via the platforms parameter is roughly an O(n) operation, meaning performance will linearly get worse as you add more sprites. If you add your static sprites via the walls parameter, then it is nearly O(1) and there is essentially no difference between for example 100 and 50,000 non-moving sprites.

We also see here some new syntax relating to our Scene object. You can access the scene like you would a Python dictionary in order to get your SpriteLists from it. There are multiple ways to access the SpriteLists within a Scene but this is the easiest and most straight forward. You could alternatively use scene.get_sprite_list("My Layer").

Then, modify the key down and key up event handlers. We’ll remove the up/down statements we had before, and make ‘UP’ jump when pressed.

05_add_gravity.py - Add Gravity#
 1        self.scene.draw()
 2
 3    def on_key_press(self, key, modifiers):
 4        """Called whenever a key is pressed."""
 5
 6        if key == arcade.key.UP or key == arcade.key.W:
 7            if self.physics_engine.can_jump():
 8                self.player_sprite.change_y = PLAYER_JUMP_SPEED
 9        elif key == arcade.key.LEFT or key == arcade.key.A:
10            self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
11        elif key == arcade.key.RIGHT or key == arcade.key.D:
12            self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
13
14    def on_key_release(self, key, modifiers):
15        """Called when the user releases a key."""
16
17        if key == arcade.key.LEFT or key == arcade.key.A:
18            self.player_sprite.change_x = 0

Note

You can change how the user jumps by changing the gravity and jump constants. Lower values for both will make for a more “floaty” character. Higher values make for a faster-paced game.

Source Code#

05_add_gravity.py - Add Gravity#
  1"""
  2Platformer Game
  3
  4python -m arcade.examples.platform_tutorial.05_add_gravity 
  5"""
  6import arcade
  7
  8# Constants
  9SCREEN_WIDTH = 1000
 10SCREEN_HEIGHT = 650
 11SCREEN_TITLE = "Platformer"
 12
 13# Constants used to scale our sprites from their original size
 14CHARACTER_SCALING = 1
 15TILE_SCALING = 0.5
 16
 17# Movement speed of player, in pixels per frame
 18PLAYER_MOVEMENT_SPEED = 5
 19GRAVITY = 1
 20PLAYER_JUMP_SPEED = 20
 21
 22
 23class MyGame(arcade.Window):
 24    """
 25    Main application class.
 26    """
 27
 28    def __init__(self):
 29
 30        # Call the parent class and set up the window
 31        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
 32
 33        # Our Scene Object
 34        self.scene = None
 35
 36        # Separate variable that holds the player sprite
 37        self.player_sprite = None
 38
 39        # Our physics engine
 40        self.physics_engine = None
 41
 42        arcade.set_background_color(arcade.csscolor.CORNFLOWER_BLUE)
 43
 44    def setup(self):
 45        """Set up the game here. Call this function to restart the game."""
 46
 47        # Initialize Scene
 48        self.scene = arcade.Scene()
 49
 50        # Set up the player, specifically placing it at these coordinates.
 51        image_source = ":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"
 52        self.player_sprite = arcade.Sprite(image_source, CHARACTER_SCALING)
 53        self.player_sprite.center_x = 64
 54        self.player_sprite.center_y = 128
 55        self.scene.add_sprite("Player", self.player_sprite)
 56
 57        # Create the ground
 58        # This shows using a loop to place multiple sprites horizontally
 59        for x in range(0, 1250, 64):
 60            wall = arcade.Sprite(":resources:images/tiles/grassMid.png", TILE_SCALING)
 61            wall.center_x = x
 62            wall.center_y = 32
 63            self.scene.add_sprite("Walls", wall)
 64
 65        # Put some crates on the ground
 66        # This shows using a coordinate list to place sprites
 67        coordinate_list = [[512, 96], [256, 96], [768, 96]]
 68
 69        for coordinate in coordinate_list:
 70            # Add a crate on the ground
 71            wall = arcade.Sprite(
 72                ":resources:images/tiles/boxCrate_double.png", TILE_SCALING
 73            )
 74            wall.position = coordinate
 75            self.scene.add_sprite("Walls", wall)
 76
 77        # Create the 'physics engine'
 78        self.physics_engine = arcade.PhysicsEnginePlatformer(
 79            self.player_sprite, gravity_constant=GRAVITY, walls=self.scene["Walls"]
 80        )
 81
 82    def on_draw(self):
 83        """Render the screen."""
 84
 85        # Clear the screen to the background color
 86        self.clear()
 87
 88        # Draw our Scene
 89        self.scene.draw()
 90
 91    def on_key_press(self, key, modifiers):
 92        """Called whenever a key is pressed."""
 93
 94        if key == arcade.key.UP or key == arcade.key.W:
 95            if self.physics_engine.can_jump():
 96                self.player_sprite.change_y = PLAYER_JUMP_SPEED
 97        elif key == arcade.key.LEFT or key == arcade.key.A:
 98            self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
 99        elif key == arcade.key.RIGHT or key == arcade.key.D:
100            self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
101
102    def on_key_release(self, key, modifiers):
103        """Called when the user releases a key."""
104
105        if key == arcade.key.LEFT or key == arcade.key.A:
106            self.player_sprite.change_x = 0
107        elif key == arcade.key.RIGHT or key == arcade.key.D:
108            self.player_sprite.change_x = 0
109
110    def on_update(self, delta_time):
111        """Movement and game logic"""
112
113        # Move the player with the physics engine
114        self.physics_engine.update()
115
116
117def main():
118    """Main function"""
119    window = MyGame()
120    window.setup()
121    arcade.run()
122
123
124if __name__ == "__main__":
125    main()