Camera Shake

Screen shot of using a scrolling window

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 camera that will follow the player sprite.
 56        self.camera_sprites = arcade.Camera2D()
 57
 58        self.camera_shake = arcade.camera.grips.ScreenShake2D(
 59            self.camera_sprites.view_data,
 60            max_amplitude=15.0,
 61            acceleration_duration=0.1,
 62            falloff_time=0.5,
 63            shake_frequency=10.0,
 64        )
 65
 66        self.explosion_sound = arcade.load_sound(":resources:sounds/explosion1.wav")
 67
 68    def setup(self):
 69        """Set up the game and initialize the variables."""
 70
 71        # Sprite lists
 72        self.player_list = arcade.SpriteList()
 73        self.wall_list = arcade.SpriteList()
 74        self.bomb_list = arcade.SpriteList()
 75
 76        # Set up the player
 77        self.player_sprite = arcade.Sprite(
 78            ":resources:images/animated_characters/female_person/femalePerson_idle.png",
 79            scale=0.4,
 80        )
 81        self.player_sprite.center_x = 512
 82        self.player_sprite.center_y = 512
 83        self.player_list.append(self.player_sprite)
 84
 85        # -- Set up several columns of walls
 86        for x in range(200, PLAYING_FIELD_WIDTH, 210):
 87            for y in range(0, PLAYING_FIELD_HEIGHT, 64):
 88                # Randomly skip a box so the player can find a way through
 89                if random.randrange(5) > 0:
 90                    wall = arcade.Sprite(
 91                        ":resources:images/tiles/grassCenter.png",
 92                        scale=SPRITE_SCALING,
 93                    )
 94                    wall.center_x = x
 95                    wall.center_y = y
 96                    self.wall_list.append(wall)
 97
 98        for i in range(BOMB_COUNT):
 99            bomb = arcade.Sprite(":resources:images/tiles/bomb.png", scale=0.25)
100            placed = False
101            while not placed:
102                bomb.center_x = random.randrange(PLAYING_FIELD_WIDTH)
103                bomb.center_y = random.randrange(PLAYING_FIELD_HEIGHT)
104                if not arcade.check_for_collision_with_list(bomb, self.wall_list):
105                    placed = True
106            self.bomb_list.append(bomb)
107
108        self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)
109
110        # Set the background color
111        self.background_color = arcade.color.AMAZON
112
113    def on_draw(self):
114        """
115        Render the screen.
116        """
117
118        # This command has to happen before we start drawing
119        self.clear()
120
121        # Select the camera we'll use to draw all our sprites
122        self.camera_shake.update_camera()
123        self.camera_sprites.use()
124
125        # Draw all the sprites.
126        self.wall_list.draw()
127        self.bomb_list.draw()
128        self.player_list.draw()
129
130        # Readjust the camera's screen_shake
131        self.camera_shake.readjust_camera()
132
133    def on_key_press(self, key, modifiers):
134        """Called whenever a key is pressed. """
135
136        if key == arcade.key.UP:
137            self.player_sprite.change_y = PLAYER_MOVEMENT_SPEED
138        elif key == arcade.key.DOWN:
139            self.player_sprite.change_y = -PLAYER_MOVEMENT_SPEED
140        elif key == arcade.key.LEFT:
141            self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
142        elif key == arcade.key.RIGHT:
143            self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
144
145    def on_key_release(self, key, modifiers):
146        """Called when the user releases a key. """
147
148        if key == arcade.key.UP or key == arcade.key.DOWN:
149            self.player_sprite.change_y = 0
150        elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
151            self.player_sprite.change_x = 0
152
153    def on_update(self, delta_time):
154        """ Movement and game logic """
155
156        # Call update on all sprites (The sprites don't do much in this
157        # example though.)
158        self.physics_engine.update()
159        self.camera_shake.update(delta_time)
160
161        # Scroll the screen to the player
162        self.scroll_to_player()
163
164        hit_list = arcade.check_for_collision_with_list(self.player_sprite, self.bomb_list)
165        for bomb in hit_list:
166            # Remove the bomb and go 'boom'
167            bomb.remove_from_sprite_lists()
168            self.explosion_sound.play()
169
170            self.camera_shake.start()
171
172    def scroll_to_player(self):
173        """
174        Scroll the window to the player.
175
176        if CAMERA_SPEED is 1, the camera will immediately move to the desired position.
177        Anything between 0 and 1 will have the camera move to the location with a smoother
178        pan.
179        """
180
181        position = (
182            self.player_sprite.center_x,
183            self.player_sprite.center_y
184        )
185        self.camera_sprites.position = arcade.math.lerp_2d(
186            self.camera_sprites.position,
187            position,
188            CAMERA_SPEED,
189        )
190
191    def on_resize(self, width: int, height: int):
192        """
193        Resize window
194        Handle the user grabbing the edge and resizing the window.
195        """
196        super().on_resize(width, height)
197        self.camera_sprites.match_window()
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, resizable=True)
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()