Acceleration and Friction

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