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, Arcade provides arcade.SimpleCamera and arcade.Camera. They both do the same base thing, but Camera has a bit of extra functionality that SimpleCamera doesn’t. For now, we will just use the SimpleCamera.

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.SimpleCamera(viewport=(0, 0, self.width, self.height))

The viewport parameter here defines the size of the camera. In most circumstances, you will want this to be the size of your window. So we specify the bottom and left coordinates of our camera viewport as (0, 0), and provide it the width and height of our window.

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.center(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
  9SCREEN_WIDTH = 800
 10SCREEN_HEIGHT = 600
 11SCREEN_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 MyGame(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__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_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(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png")
 55
 56        self.player_sprite = arcade.Sprite(self.player_texture)
 57        self.player_sprite.center_x = 64
 58        self.player_sprite.center_y = 128
 59
 60        self.player_list = arcade.SpriteList()
 61        self.player_list.append(self.player_sprite)
 62
 63        self.wall_list = arcade.SpriteList(use_spatial_hash=True)
 64
 65        # Create the ground
 66        # This shows using a loop to place multiple sprites horizontally
 67        for x in range(0, 1250, 64):
 68            wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=TILE_SCALING)
 69            wall.center_x = x
 70            wall.center_y = 32
 71            self.wall_list.append(wall)
 72
 73        # Put some crates on the ground
 74        # This shows using a coordinate list to place sprites
 75        coordinate_list = [[512, 96], [256, 96], [768, 96]]
 76
 77        for coordinate in coordinate_list:
 78            # Add a crate on the ground
 79            wall = arcade.Sprite(
 80                ":resources:images/tiles/boxCrate_double.png", scale=TILE_SCALING
 81            )
 82            wall.position = coordinate
 83            self.wall_list.append(wall)
 84
 85        # Create a Platformer Physics Engine, this will handle moving our
 86        # player as well as collisions between the player sprite and
 87        # whatever SpriteList we specify for the walls.
 88        # It is important to supply static to the walls parameter. There is a
 89        # platforms parameter that is intended for moving platforms.
 90        # If a platform is supposed to move, and is added to the walls list,
 91        # it will not be moved.
 92        self.physics_engine = arcade.PhysicsEnginePlatformer(
 93            self.player_sprite, walls=self.wall_list, gravity_constant=GRAVITY
 94        )
 95
 96        # Initialize our camera, setting a viewport the size of our window.
 97        self.camera = arcade.SimpleCamera(viewport=(0, 0, self.width, self.height))
 98
 99        self.background_color = arcade.csscolor.CORNFLOWER_BLUE
100
101    def on_draw(self):
102        """Render the screen."""
103
104        # Clear the screen to the background color
105        self.clear()
106
107        # Activate our camera before drawing
108        self.camera.use()
109
110        # Draw our sprites
111        self.player_list.draw()
112        self.wall_list.draw()
113
114    def on_update(self, delta_time):
115        """Movement and Game Logic"""
116
117        # Move the player using our physics engine
118        self.physics_engine.update()
119
120        # Center our camera on the player
121        self.camera.center(self.player_sprite.position)
122
123    def on_key_press(self, key, modifiers):
124        """Called whenever a key is pressed."""
125
126        if key == arcade.key.ESCAPE:
127            self.setup()
128
129        if key == arcade.key.UP or key == arcade.key.W:
130            if self.physics_engine.can_jump():
131                self.player_sprite.change_y = PLAYER_JUMP_SPEED
132
133        if key == arcade.key.LEFT or key == arcade.key.A:
134            self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
135        elif key == arcade.key.RIGHT or key == arcade.key.D:
136            self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
137
138    def on_key_release(self, key, modifiers):
139        """Called whenever a key is released."""
140
141        if key == arcade.key.LEFT or key == arcade.key.A:
142            self.player_sprite.change_x = 0
143        elif key == arcade.key.RIGHT or key == arcade.key.D:
144            self.player_sprite.change_x = 0
145
146
147def main():
148    """Main function"""
149    window = MyGame()
150    window.setup()
151    arcade.run()
152
153
154if __name__ == "__main__":
155    main()

Run This Chapter#

python -m arcade.examples.platform_tutorial.07_camera