Camera Shake

You can cause the camera to shake, as this example does when the player encounters a bomb. See the highlighted lines below.
sprite_move_scrolling_shake.py
1"""
2Scroll around a large screen.
3
4Artwork from https://kenney.nl
5
6If Python and Arcade are installed, this example can be run from the command line with:
7python -m arcade.examples.sprite_move_scrolling_shake
8"""
9
10import random
11# import math
12import arcade
13
14SPRITE_SCALING = 0.5
15
16WINDOW_WIDTH = 1289
17WINDOW_HEIGHT = 720
18WINDOW_TITLE = "Camera Shake Example"
19
20# How many pixels to keep as a minimum margin between the character
21# and the edge of the screen.
22VIEWPORT_MARGIN = 220
23
24# How fast the camera pans to the player. 1.0 is instant.
25CAMERA_SPEED = 0.1
26
27# How fast the character moves
28PLAYER_MOVEMENT_SPEED = 7
29
30BOMB_COUNT = 50
31PLAYING_FIELD_WIDTH = 1600
32PLAYING_FIELD_HEIGHT = 1600
33
34
35class GameView(arcade.View):
36 """ Main application class. """
37
38 def __init__(self):
39 """
40 Initializer
41 """
42 super().__init__()
43
44 # Sprite lists
45 self.player_list = None
46 self.wall_list = None
47 self.bomb_list = None
48
49 # Set up the player
50 self.player_sprite = None
51
52 # Physics engine so we don't run into walls.
53 self.physics_engine = None
54
55 # Create the cameras. One for the GUI, one for the sprites.
56 # We scroll the 'sprite world' but not the GUI.
57 self.camera_sprites = arcade.camera.Camera2D()
58 self.camera_gui = arcade.camera.Camera2D()
59
60 self.camera_shake = arcade.camera.grips.ScreenShake2D(
61 self.camera_sprites.view_data,
62 max_amplitude=15.0,
63 acceleration_duration=0.1,
64 falloff_time=0.5,
65 shake_frequency=10.0,
66 )
67
68 self.explosion_sound = arcade.load_sound(":resources:sounds/explosion1.wav")
69
70 def setup(self):
71 """Set up the game and initialize the variables."""
72
73 # Sprite lists
74 self.player_list = arcade.SpriteList()
75 self.wall_list = arcade.SpriteList()
76 self.bomb_list = arcade.SpriteList()
77
78 # Set up the player
79 self.player_sprite = arcade.Sprite(
80 ":resources:images/animated_characters/female_person/femalePerson_idle.png",
81 scale=0.4,
82 )
83 self.player_sprite.center_x = 512
84 self.player_sprite.center_y = 512
85 self.player_list.append(self.player_sprite)
86
87 # -- Set up several columns of walls
88 for x in range(200, PLAYING_FIELD_WIDTH, 210):
89 for y in range(0, PLAYING_FIELD_HEIGHT, 64):
90 # Randomly skip a box so the player can find a way through
91 if random.randrange(5) > 0:
92 wall = arcade.Sprite(
93 ":resources:images/tiles/grassCenter.png",
94 scale=SPRITE_SCALING,
95 )
96 wall.center_x = x
97 wall.center_y = y
98 self.wall_list.append(wall)
99
100 for i in range(BOMB_COUNT):
101 bomb = arcade.Sprite(":resources:images/tiles/bomb.png", scale=0.25)
102 placed = False
103 while not placed:
104 bomb.center_x = random.randrange(PLAYING_FIELD_WIDTH)
105 bomb.center_y = random.randrange(PLAYING_FIELD_HEIGHT)
106 if not arcade.check_for_collision_with_list(bomb, self.wall_list):
107 placed = True
108 self.bomb_list.append(bomb)
109
110 self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)
111
112 # Set the background color
113 self.background_color = arcade.color.AMAZON
114
115 def on_draw(self):
116 """
117 Render the screen.
118 """
119
120 # This command has to happen before we start drawing
121 self.clear()
122
123 # Select the camera we'll use to draw all our sprites
124 self.camera_shake.update_camera()
125 self.camera_sprites.use()
126
127 # Draw all the sprites.
128 self.wall_list.draw()
129 self.bomb_list.draw()
130 self.player_list.draw()
131
132 # Readjust the camera's screen_shake
133 self.camera_shake.readjust_camera()
134
135 def on_key_press(self, key, modifiers):
136 """Called whenever a key is pressed. """
137
138 if key == arcade.key.UP:
139 self.player_sprite.change_y = PLAYER_MOVEMENT_SPEED
140 elif key == arcade.key.DOWN:
141 self.player_sprite.change_y = -PLAYER_MOVEMENT_SPEED
142 elif key == arcade.key.LEFT:
143 self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
144 elif key == arcade.key.RIGHT:
145 self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
146
147 def on_key_release(self, key, modifiers):
148 """Called when the user releases a key. """
149
150 if key == arcade.key.UP or key == arcade.key.DOWN:
151 self.player_sprite.change_y = 0
152 elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
153 self.player_sprite.change_x = 0
154
155 def on_update(self, delta_time):
156 """ Movement and game logic """
157
158 # Call update on all sprites (The sprites don't do much in this
159 # example though.)
160 self.physics_engine.update()
161 self.camera_shake.update(delta_time)
162
163 # Scroll the screen to the player
164 self.scroll_to_player()
165
166 hit_list = arcade.check_for_collision_with_list(self.player_sprite, self.bomb_list)
167 for bomb in hit_list:
168 # Remove the bomb and go 'boom'
169 bomb.remove_from_sprite_lists()
170 self.explosion_sound.play()
171
172 self.camera_shake.start()
173
174 def scroll_to_player(self):
175 """
176 Scroll the window to the player.
177
178 if CAMERA_SPEED is 1, the camera will immediately move to the desired position.
179 Anything between 0 and 1 will have the camera move to the location with a smoother
180 pan.
181 """
182
183 position = (
184 self.player_sprite.center_x,
185 self.player_sprite.center_y
186 )
187 self.camera_sprites.position = arcade.math.lerp_2d(
188 self.camera_sprites.position,
189 position,
190 CAMERA_SPEED,
191 )
192
193 def on_resize(self, width: int, height: int):
194 """
195 Resize window
196 Handle the user grabbing the edge and resizing the window.
197 """
198 super().on_resize(width, height)
199 self.camera_sprites.match_window()
200 self.camera_gui.match_window(position=True)
201
202
203def main():
204 """ Main function """
205 # Create a window class. This is what actually shows up on screen
206 window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
207
208 # Create and setup the GameView
209 game = GameView()
210 game.setup()
211
212 # Show GameView on screen
213 window.show_view(game)
214
215 # Start the arcade game loop
216 arcade.run()
217
218
219if __name__ == "__main__":
220 main()