Step 6 - Add a Camera#

We can have our window be a small viewport into a much larger world by adding a camera to it.

First we need to create a new variable in our __init__ method:

06_camera.py - Create camera variable#

        # Our physics engine

Next we can initialize the camera in the setup function:

06_camera.py - Setup Camera#

    def setup(self):

Then to use our camera when drawing, we can activate it in our on_draw function:

06_camera.py - Use camera when drawing#

        # Clear the screen to the background color

Now at this point everything should be working the same, but the camera can do a lot more than this. We can use the move function of the camera to scroll it to a different position. We can use this functionality to keep the camera centered on the player:

We can create a function to calculate the coordinates for the center of our player relative to the screen, then move the camera to those. Then we can call that function in on_update to actually move it. The new position will be taken into account during the use function in on_draw

06_camera.py - Center camera on player#
            self.player_sprite.change_x = 0
        elif key == arcade.key.RIGHT or key == arcade.key.D:
            self.player_sprite.change_x = 0

    def center_camera_to_player(self):
        screen_center_x = self.player_sprite.center_x - (self.camera.viewport_width / 2)
        screen_center_y = self.player_sprite.center_y - (
            self.camera.viewport_height / 2
        )

        # Don't let camera travel past 0
        if screen_center_x < 0:
            screen_center_x = 0
        if screen_center_y < 0:
            screen_center_y = 0
        player_centered = screen_center_x, screen_center_y

        self.camera.move_to(player_centered)

    def on_update(self, delta_time):
        """Movement and game logic"""

        # Move the player with the physics engine

Source Code#

Add a Camera#
  1"""
  2Platformer Game
  3
  4python -m arcade.examples.platform_tutorial.06_camera
  5"""
  6from __future__ import annotations
  7
  8import arcade
  9
 10# Constants
 11SCREEN_WIDTH = 1000
 12SCREEN_HEIGHT = 650
 13SCREEN_TITLE = "Platformer"
 14
 15# Constants used to scale our sprites from their original size
 16CHARACTER_SCALING = 1
 17TILE_SCALING = 0.5
 18
 19# Movement speed of player, in pixels per frame
 20PLAYER_MOVEMENT_SPEED = 5
 21GRAVITY = 1
 22PLAYER_JUMP_SPEED = 20
 23
 24
 25class MyGame(arcade.Window):
 26    """
 27    Main application class.
 28    """
 29
 30    def __init__(self):
 31
 32        # Call the parent class and set up the window
 33        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
 34
 35        # Our Scene Object
 36        self.scene = None
 37
 38        # Separate variable that holds the player sprite
 39        self.player_sprite = None
 40
 41        # Our physics engine
 42        self.physics_engine = None
 43
 44        # A Camera that can be used for scrolling the screen
 45        self.camera = None
 46
 47        self.background_color = arcade.csscolor.CORNFLOWER_BLUE
 48
 49    def setup(self):
 50        """Set up the game here. Call this function to restart the game."""
 51
 52        # Set up the Camera
 53        self.camera = arcade.SimpleCamera(viewport=(0, 0, self.width, self.height))
 54
 55        # Initialize Scene
 56        self.scene = arcade.Scene()
 57
 58        # Create the Sprite lists
 59        self.scene.add_sprite_list("Player")
 60        self.scene.add_sprite_list("Walls", use_spatial_hash=True)
 61
 62        # Set up the player, specifically placing it at these coordinates.
 63        image_source = ":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"
 64        self.player_sprite = arcade.Sprite(image_source, CHARACTER_SCALING)
 65        self.player_sprite.center_x = 64
 66        self.player_sprite.center_y = 96
 67        self.scene.add_sprite("Player", self.player_sprite)
 68
 69        # Create the ground
 70        # This shows using a loop to place multiple sprites horizontally
 71        for x in range(0, 1250, 64):
 72            wall = arcade.Sprite(":resources:images/tiles/grassMid.png", TILE_SCALING)
 73            wall.center_x = x
 74            wall.center_y = 32
 75            self.scene.add_sprite("Walls", wall)
 76
 77        # Put some crates on the ground
 78        # This shows using a coordinate list to place sprites
 79        coordinate_list = [[512, 96], [256, 96], [768, 96]]
 80
 81        for coordinate in coordinate_list:
 82            # Add a crate on the ground
 83            wall = arcade.Sprite(
 84                ":resources:images/tiles/boxCrate_double.png", TILE_SCALING
 85            )
 86            wall.position = coordinate
 87            self.scene.add_sprite("Walls", wall)
 88
 89        # Create the 'physics engine'
 90        self.physics_engine = arcade.PhysicsEnginePlatformer(
 91            self.player_sprite, gravity_constant=GRAVITY, walls=self.scene["Walls"]
 92        )
 93
 94    def on_draw(self):
 95        """Render the screen."""
 96
 97        # Clear the screen to the background color
 98        self.clear()
 99
100        # Activate our Camera
101        self.camera.use()
102
103        # Draw our Scene
104        self.scene.draw()
105
106    def on_key_press(self, key, modifiers):
107        """Called whenever a key is pressed."""
108
109        if key == arcade.key.UP or key == arcade.key.W:
110            if self.physics_engine.can_jump():
111                self.player_sprite.change_y = PLAYER_JUMP_SPEED
112        elif key == arcade.key.LEFT or key == arcade.key.A:
113            self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
114        elif key == arcade.key.RIGHT or key == arcade.key.D:
115            self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
116
117    def on_key_release(self, key, modifiers):
118        """Called when the user releases a key."""
119
120        if key == arcade.key.LEFT or key == arcade.key.A:
121            self.player_sprite.change_x = 0
122        elif key == arcade.key.RIGHT or key == arcade.key.D:
123            self.player_sprite.change_x = 0
124
125    def center_camera_to_player(self):
126        screen_center_x = self.player_sprite.center_x - (self.camera.viewport_width / 2)
127        screen_center_y = self.player_sprite.center_y - (
128            self.camera.viewport_height / 2
129        )
130
131        # Don't let camera travel past 0
132        if screen_center_x < 0:
133            screen_center_x = 0
134        if screen_center_y < 0:
135            screen_center_y = 0
136        player_centered = screen_center_x, screen_center_y
137
138        self.camera.move_to(player_centered)
139
140    def on_update(self, delta_time):
141        """Movement and game logic"""
142
143        # Move the player with the physics engine
144        self.physics_engine.update()
145
146        # Position the camera
147        self.center_camera_to_player()
148
149
150def main():
151    """Main function"""
152    window = MyGame()
153    window.setup()
154    arcade.run()
155
156
157if __name__ == "__main__":
158    main()