Step 4 - Add User Control#
Now we need to be able to get the user to move around.
First, at the top of the program add a constant that controls how many pixels per update our character travels:
# Constants used to scale our sprites from their original size
CHARACTER_SCALING = 1
Next, at the end of our setup
method, we need to create a physics engine that will
move our player and keep her from running through walls. The PhysicsEngineSimple
class takes two parameters: The moving
sprite, and a list of sprites the moving sprite can’t move through.
For more information about the physics engine we are using in this tutorial,
see arcade.PhysicsEngineSimple
.
Note
It is possible to have multiple physics engines, one per moving sprite. These are very simple, but easy physics engines. See Pymunk Platformer for a more advanced physics engine.
)
wall.position = coordinate
self.scene.add_sprite("Walls", wall)
Each sprite has center_x
and center_y
attributes. Changing these will
change the location of the sprite. (There are also attributes for top, bottom,
left, right, and angle that will move the sprite.)
Each sprite has change_x
and change_y
variables. These can be used to
hold the velocity that the sprite is moving with. We will adjust these
based on what key the user hits. If the user hits the right arrow key
we want a positive value for change_x
. If the value is 5, it will move
5 pixels per frame.
In this case, when the user presses a key we’ll change the sprites change x and y. The physics engine will look at that, and move the player unless she’ll hit a wall.
1 def on_key_press(self, key, modifiers):
2 """Called whenever a key is pressed."""
3
4 if key == arcade.key.UP or key == arcade.key.W:
5 self.player_sprite.change_y = PLAYER_MOVEMENT_SPEED
6 elif key == arcade.key.DOWN or key == arcade.key.S:
7 self.player_sprite.change_y = -PLAYER_MOVEMENT_SPEED
8 elif key == arcade.key.LEFT or key == arcade.key.A:
9 self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
10 elif key == arcade.key.RIGHT or key == arcade.key.D:
11 self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
On releasing the key, we’ll put our speed back to zero.
1 def on_key_release(self, key, modifiers):
2 """Called when the user releases a key."""
3
4 if key == arcade.key.UP or key == arcade.key.W:
5 self.player_sprite.change_y = 0
6 elif key == arcade.key.DOWN or key == arcade.key.S:
7 self.player_sprite.change_y = 0
8 elif key == arcade.key.LEFT or key == arcade.key.A:
9 self.player_sprite.change_x = 0
10 elif key == arcade.key.RIGHT or key == arcade.key.D:
11 self.player_sprite.change_x = 0
Note
This method of tracking the speed to the key the player presses is simple, but isn’t perfect. If the player hits both left and right keys at the same time, then lets off the left one, we expect the player to move right. This method won’t support that. If you want a slightly more complex method that does, see Better Move By Keyboard.
Our on_update
method is called about 60 times per second. We’ll ask the physics
engine to move our player based on her change_x
and change_y
.
1 def on_update(self, delta_time):
2 """Movement and game logic"""
3
4 # Move the player with the physics engine
5 self.physics_engine.update()
Source Code#
1"""
2Platformer Game
3
4python -m arcade.examples.platform_tutorial.04_user_control
5"""
6from __future__ import annotations
7
8import arcade
9
10# Constants
11SCREEN_WIDTH = 1000
12SCREEN_HEIGHT = 650
13SCREEN_TITLE = "Platformer"
14
15# Constants used to scale our sprites from their original size
16CHARACTER_SCALING = 1
17TILE_SCALING = 0.5
18
19# Movement speed of player, in pixels per frame
20PLAYER_MOVEMENT_SPEED = 5
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 self.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.PhysicsEngineSimple(
79 self.player_sprite, self.scene.get_sprite_list("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 self.player_sprite.change_y = PLAYER_MOVEMENT_SPEED
96 elif key == arcade.key.DOWN or key == arcade.key.S:
97 self.player_sprite.change_y = -PLAYER_MOVEMENT_SPEED
98 elif key == arcade.key.LEFT or key == arcade.key.A:
99 self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
100 elif key == arcade.key.RIGHT or key == arcade.key.D:
101 self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
102
103 def on_key_release(self, key, modifiers):
104 """Called when the user releases a key."""
105
106 if key == arcade.key.UP or key == arcade.key.W:
107 self.player_sprite.change_y = 0
108 elif key == arcade.key.DOWN or key == arcade.key.S:
109 self.player_sprite.change_y = 0
110 elif key == arcade.key.LEFT or key == arcade.key.A:
111 self.player_sprite.change_x = 0
112 elif key == arcade.key.RIGHT or key == arcade.key.D:
113 self.player_sprite.change_x = 0
114
115 def on_update(self, delta_time):
116 """Movement and game logic"""
117
118 # Move the player with the physics engine
119 self.physics_engine.update()
120
121
122def main():
123 """Main function"""
124 window = MyGame()
125 window.setup()
126 arcade.run()
127
128
129if __name__ == "__main__":
130 main()