Step 5 - Add Gravity
The previous example is great for top-down games, 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.
GRAVITY = 1
PLAYER_JUMP_SPEED = 20
Now, let’s change the Physics Engine we created in the __init__
function to a
arcade.PhysicsEnginePlatformer
instead of a arcade.PhysicsEngineSimple
.
This new physics engine will handle jumping and gravity for us, and will do even more
in later chapters.
self.physics_engine = arcade.PhysicsEnginePlatformer(
self.player_sprite, walls=self.wall_list, gravity_constant=GRAVITY
)
This is very similar to how we created the original simple physics engine, with two exceptions.
The first being that we have sent it our gravity constant. The second being that we have explicitly
sent our wall SpriteList to the walls
parameter. This is a very important step. The platformer
physics engine has two parameters for collidable objects, one named platforms
and one named walls
.
The difference is that objects sent to platforms
are intended to be moved. They are moved in the same
way the player is, by modifying their change_x
and change_y
values. Objects sent to the
walls
parameter will not be moved. The reason this is so important is that non-moving walls have much
faster performance than movable platforms.
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.
Lastly we will give our player the ability to jump. Modify the on_key_press
and on_key_release
functions.
We’ll remove the up/down statements we had before, and make UP
jump when pressed.
if key == arcade.key.UP or key == arcade.key.W:
if self.physics_engine.can_jump():
self.player_sprite.change_y = PLAYER_JUMP_SPEED
The can_jump()
check from our physics engine will make it so that we can only jump if we are touching the
ground. You can remove this function to allow jumping in mid-air for some interesting results. Think about how
you might implement a double-jump system using this.
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
1"""
2Platformer Game
3
4python -m arcade.examples.platform_tutorial.05_add_gravity
5"""
6import arcade
7
8# Constants
9WINDOW_WIDTH = 1280
10WINDOW_HEIGHT = 720
11WINDOW_TITLE = "Platformer"
12
13# Constants used to scale our sprites from their original size
14TILE_SCALING = 0.5
15
16# Movement speed of player, in pixels per frame
17PLAYER_MOVEMENT_SPEED = 5
18GRAVITY = 1
19PLAYER_JUMP_SPEED = 20
20
21
22class GameView(arcade.Window):
23 """
24 Main application class.
25 """
26
27 def __init__(self):
28
29 # Call the parent class and set up the window
30 super().__init__(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
31
32 # Variable to hold our texture for our player
33 self.player_texture = arcade.load_texture(
34 ":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"
35 )
36
37 # Separate variable that holds the player sprite
38 self.player_sprite = arcade.Sprite(self.player_texture)
39 self.player_sprite.center_x = 64
40 self.player_sprite.center_y = 128
41
42 # SpriteList for our player
43 self.player_list = arcade.SpriteList()
44 self.player_list.append(self.player_sprite)
45
46 # SpriteList for our boxes and ground
47 # Putting our ground and box Sprites in the same SpriteList
48 # will make it easier to perform collision detection against
49 # them later on. Setting the spatial hash to True will make
50 # collision detection much faster if the objects in this
51 # SpriteList do not move.
52 self.wall_list = arcade.SpriteList(use_spatial_hash=True)
53
54 # Create the ground
55 # This shows using a loop to place multiple sprites horizontally
56 for x in range(0, 1250, 64):
57 wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=TILE_SCALING)
58 wall.center_x = x
59 wall.center_y = 32
60 self.wall_list.append(wall)
61
62 # Put some crates on the ground
63 # This shows using a coordinate list to place sprites
64 coordinate_list = [[512, 96], [256, 96], [768, 96]]
65
66 for coordinate in coordinate_list:
67 # Add a crate on the ground
68 wall = arcade.Sprite(
69 ":resources:images/tiles/boxCrate_double.png", scale=TILE_SCALING
70 )
71 wall.position = coordinate
72 self.wall_list.append(wall)
73
74 # Create a Platformer Physics Engine.
75 # This will handle moving our player as well as collisions between
76 # the player sprite and whatever SpriteList we specify for the walls.
77 # It is important to supply static platforms to the walls parameter. There is a
78 # platforms parameter that is intended for moving platforms.
79 # If a platform is supposed to move, and is added to the walls list,
80 # it will not be moved.
81 self.physics_engine = arcade.PhysicsEnginePlatformer(
82 self.player_sprite, walls=self.wall_list, gravity_constant=GRAVITY
83 )
84
85 self.background_color = arcade.csscolor.CORNFLOWER_BLUE
86
87 def setup(self):
88 """Set up the game here. Call this function to restart the game."""
89 pass
90
91 def on_draw(self):
92 """Render the screen."""
93
94 # Clear the screen to the background color
95 self.clear()
96
97 # Draw our sprites
98 self.player_list.draw()
99 self.wall_list.draw()
100
101 def on_update(self, delta_time):
102 """Movement and Game Logic"""
103
104 # Move the player using our physics engine
105 self.physics_engine.update()
106
107 def on_key_press(self, key, modifiers):
108 """Called whenever a key is pressed."""
109
110 if key == arcade.key.UP or key == arcade.key.W:
111 if self.physics_engine.can_jump():
112 self.player_sprite.change_y = PLAYER_JUMP_SPEED
113
114 if key == arcade.key.LEFT or key == arcade.key.A:
115 self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
116 elif key == arcade.key.RIGHT or key == arcade.key.D:
117 self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
118
119 def on_key_release(self, key, modifiers):
120 """Called whenever a key is released."""
121
122 if key == arcade.key.LEFT or key == arcade.key.A:
123 self.player_sprite.change_x = 0
124 elif key == arcade.key.RIGHT or key == arcade.key.D:
125 self.player_sprite.change_x = 0
126
127
128def main():
129 """Main function"""
130 window = GameView()
131 window.setup()
132 arcade.run()
133
134
135if __name__ == "__main__":
136 main()
Run This Chapter
python -m arcade.examples.platform_tutorial.05_add_gravity