Step 7 - Adding a Camera

Now that our player can move and jump around, we need to give them a way to explore the world beyond the original window. If you’ve ever played a platformer game, you might be familiar with the concept of the screen scrolling to reveal more of the map as the player moves.

To achieve this, we can use a Camera. Since we are making a 2D game, arcade.camera.Camera2D will be easiest.

To start with, let’s go ahead and add a variable in our __init__ function to hold it:

self.camera = None

Next we can go to our setup function, and initialize it like so:

self.camera = arcade.camera.Camera2D()

Since we’re drawing to the entire screen, we can use Camera2D’s default settings. In other circumstances, we can create or adjust the camera so it has a different viewport.

In order to use our camera when drawing things to the screen, we only need to add one line to our on_draw function. This line should typically come before anything you want to draw with the camera. In later chapters, we’ll explore using multiple cameras to draw things in different positions. Go ahead and add this line before drawing our SpriteLists:

self.camera.use()

If you run the game at this point, you might notice that nothing has changed, our game is still one static un-moving screen. This is because we are never updating the camera’s position. In our platformer game, we want the camera to follow the player, and keep them in the center of the screen. Arcade provides a helpful function to do this with one line of code. In other types of games or more advanced usage you may want to set the cameras position directly in order to create interesting effects, but for now all we need is the center() function of our camera.

If we add the following line to our on_update() function and run the game, you should now see the player stay at the center of the screen, while being able to scroll the screen around to the rest of our map. For fun, see what happens if you fall off of the map! Later on, we’ll revisit a more advanced camera setup that will take the bounds of our world into consideration.

self.camera.position = self.player_sprite.position

Source Code

Adding a Camera
  1"""
  2Platformer Game
  3
  4python -m arcade.examples.platform_tutorial.07_camera
  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 = None
 34
 35        # Separate variable that holds the player sprite
 36        self.player_sprite = None
 37
 38        # SpriteList for our player
 39        self.player_list = None
 40
 41        # SpriteList for our boxes and ground
 42        # Putting our ground and box Sprites in the same SpriteList
 43        # will make it easier to perform collision detection against
 44        # them later on. Setting the spatial hash to True will make
 45        # collision detection much faster if the objects in this
 46        # SpriteList do not move.
 47        self.wall_list = None
 48
 49        # A variable to store our camera object
 50        self.camera = None
 51
 52    def setup(self):
 53        """Set up the game here. Call this function to restart the game."""
 54        self.player_texture = arcade.load_texture(
 55            ":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"
 56        )
 57
 58        self.player_sprite = arcade.Sprite(self.player_texture)
 59        self.player_sprite.center_x = 64
 60        self.player_sprite.center_y = 128
 61
 62        self.player_list = arcade.SpriteList()
 63        self.player_list.append(self.player_sprite)
 64
 65        self.wall_list = arcade.SpriteList(use_spatial_hash=True)
 66
 67        # Create the ground
 68        # This shows using a loop to place multiple sprites horizontally
 69        for x in range(0, 1250, 64):
 70            wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=TILE_SCALING)
 71            wall.center_x = x
 72            wall.center_y = 32
 73            self.wall_list.append(wall)
 74
 75        # Put some crates on the ground
 76        # This shows using a coordinate list to place sprites
 77        coordinate_list = [[512, 96], [256, 96], [768, 96]]
 78
 79        for coordinate in coordinate_list:
 80            # Add a crate on the ground
 81            wall = arcade.Sprite(
 82                ":resources:images/tiles/boxCrate_double.png", scale=TILE_SCALING
 83            )
 84            wall.position = coordinate
 85            self.wall_list.append(wall)
 86
 87        # Create a Platformer Physics Engine, this will handle moving our
 88        # player as well as collisions between the player sprite and
 89        # whatever SpriteList we specify for the walls.
 90        # It is important to supply static to the walls parameter. There is a
 91        # platforms parameter that is intended for moving platforms.
 92        # If a platform is supposed to move, and is added to the walls list,
 93        # it will not be moved.
 94        self.physics_engine = arcade.PhysicsEnginePlatformer(
 95            self.player_sprite, walls=self.wall_list, gravity_constant=GRAVITY
 96        )
 97
 98        # Initialize our camera, setting a viewport the size of our window.
 99        self.camera = arcade.camera.Camera2D()
100
101        self.background_color = arcade.csscolor.CORNFLOWER_BLUE
102
103    def on_draw(self):
104        """Render the screen."""
105
106        # Clear the screen to the background color
107        self.clear()
108
109        # Activate our camera before drawing
110        self.camera.use()
111
112        # Draw our sprites
113        self.player_list.draw()
114        self.wall_list.draw()
115
116    def on_update(self, delta_time):
117        """Movement and Game Logic"""
118
119        # Move the player using our physics engine
120        self.physics_engine.update()
121
122        # Center our camera on the player
123        self.camera.position = self.player_sprite.position
124
125    def on_key_press(self, key, modifiers):
126        """Called whenever a key is pressed."""
127
128        if key == arcade.key.ESCAPE:
129            self.setup()
130
131        if key == arcade.key.UP or key == arcade.key.W:
132            if self.physics_engine.can_jump():
133                self.player_sprite.change_y = PLAYER_JUMP_SPEED
134
135        if key == arcade.key.LEFT or key == arcade.key.A:
136            self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
137        elif key == arcade.key.RIGHT or key == arcade.key.D:
138            self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
139
140    def on_key_release(self, key, modifiers):
141        """Called whenever a key is released."""
142
143        if key == arcade.key.LEFT or key == arcade.key.A:
144            self.player_sprite.change_x = 0
145        elif key == arcade.key.RIGHT or key == arcade.key.D:
146            self.player_sprite.change_x = 0
147
148
149def main():
150    """Main function"""
151    window = GameView()
152    window.setup()
153    arcade.run()
154
155
156if __name__ == "__main__":
157    main()

Run This Chapter

python -m arcade.examples.platform_tutorial.07_camera