Move with a Scrolling Screen - Centered

Using a arcade.Camera, a program can easily scroll around a larger “world” while only showing part of it on the screen.

If you are displaying a GUI or some other items that should NOT scroll, you’ll need two cameras. One that shows the unscrolled GUI, and one that shows the scrolled sprites.

See also Move with a Scrolling Screen - Margins.

Screen shot of using a scrolling window
sprite_move_scrolling.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
  8"""
  9
 10import random
 11import arcade
 12
 13SPRITE_SCALING = 0.5
 14
 15WINDOW_WIDTH = 1280
 16WINDOW_HEIGHT = 720
 17WINDOW_TITLE = "Sprite Move with Scrolling Screen Example"
 18
 19# How many pixels to keep as a minimum margin between the character
 20# and the edge of the screen.
 21VIEWPORT_MARGIN = 220
 22
 23# How fast the camera pans to the player. 1.0 is instant.
 24CAMERA_SPEED = 0.1
 25
 26# How fast the character moves
 27PLAYER_MOVEMENT_SPEED = 7
 28
 29
 30class GameView(arcade.View):
 31    """ Main application class. """
 32
 33    def __init__(self):
 34        """
 35        Initializer
 36        """
 37        super().__init__()
 38
 39        # Sprite lists
 40        self.player_list = None
 41        self.wall_list = None
 42
 43        # Set up the player
 44        self.player_sprite = None
 45
 46        # Physics engine so we don't run into walls.
 47        self.physics_engine = None
 48
 49        # Track the current state of what key is pressed
 50        self.left_pressed = False
 51        self.right_pressed = False
 52        self.up_pressed = False
 53        self.down_pressed = False
 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    def setup(self):
 61        """ Set up the game and initialize the variables. """
 62
 63        # Sprite lists
 64        self.player_list = arcade.SpriteList()
 65        self.wall_list = arcade.SpriteList()
 66
 67        # Set up the player
 68        self.player_sprite = arcade.Sprite(
 69            ":resources:images/animated_characters/female_person/femalePerson_idle.png",
 70            scale=0.4,
 71        )
 72        self.player_sprite.center_x = 256
 73        self.player_sprite.center_y = 512
 74        self.player_list.append(self.player_sprite)
 75
 76        # -- Set up several columns of walls
 77        for x in range(200, 1650, 210):
 78            for y in range(0, 1600, 64):
 79                # Randomly skip a box so the player can find a way through
 80                if random.randrange(5) > 0:
 81                    wall = arcade.Sprite(
 82                        ":resources:images/tiles/grassCenter.png",
 83                        scale=SPRITE_SCALING,
 84                    )
 85                    wall.center_x = x
 86                    wall.center_y = y
 87                    self.wall_list.append(wall)
 88
 89        self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)
 90
 91        # Set the background color
 92        self.background_color = arcade.color.AMAZON
 93
 94    def on_draw(self):
 95        """ Render the screen. """
 96
 97        # This command has to happen before we start drawing
 98        self.clear()
 99
100        # Select the camera we'll use to draw all our sprites
101        self.camera_sprites.use()
102
103        # Draw all the sprites.
104        self.wall_list.draw()
105        self.player_list.draw()
106
107        # Select the (unscrolled) camera for our GUI
108        self.camera_gui.use()
109
110        # Draw the GUI
111        arcade.draw_rect_filled(arcade.rect.XYWH(self.width // 2, 20, self.width, 40),
112                                arcade.color.ALMOND)
113        text = f"Scroll value: ({self.camera_sprites.position[0]:5.1f}, " \
114               f"{self.camera_sprites.position[1]:5.1f})"
115        arcade.draw_text(text, 10, 10, arcade.color.BLACK_BEAN, 20)
116
117    def on_key_press(self, key, modifiers):
118        """Called whenever a key is pressed. """
119
120        if key == arcade.key.UP:
121            self.up_pressed = True
122        elif key == arcade.key.DOWN:
123            self.down_pressed = True
124        elif key == arcade.key.LEFT:
125            self.left_pressed = True
126        elif key == arcade.key.RIGHT:
127            self.right_pressed = True
128
129    def on_key_release(self, key, modifiers):
130        """Called when the user releases a key. """
131
132        if key == arcade.key.UP:
133            self.up_pressed = False
134        elif key == arcade.key.DOWN:
135            self.down_pressed = False
136        elif key == arcade.key.LEFT:
137            self.left_pressed = False
138        elif key == arcade.key.RIGHT:
139            self.right_pressed = False
140
141    def on_update(self, delta_time):
142        """ Movement and game logic """
143
144        # Calculate speed based on the keys pressed
145        self.player_sprite.change_x = 0
146        self.player_sprite.change_y = 0
147
148        if self.up_pressed and not self.down_pressed:
149            self.player_sprite.change_y = PLAYER_MOVEMENT_SPEED
150        elif self.down_pressed and not self.up_pressed:
151            self.player_sprite.change_y = -PLAYER_MOVEMENT_SPEED
152        if self.left_pressed and not self.right_pressed:
153            self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
154        elif self.right_pressed and not self.left_pressed:
155            self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
156
157        # Call update on all sprites (The sprites don't do much in this
158        # example though.)
159        self.physics_engine.update()
160
161        # Scroll the screen to the player
162        self.scroll_to_player()
163
164    def scroll_to_player(self):
165        """
166        Scroll the window to the player.
167
168        if CAMERA_SPEED is 1, the camera will immediately move to the desired
169        position. Anything between 0 and 1 will have the camera move to the
170        location with a smoother pan.
171        """
172
173        position = (self.player_sprite.center_x, self.player_sprite.center_y)
174        self.camera_sprites.position = arcade.math.lerp_2d(
175            self.camera_sprites.position, position, CAMERA_SPEED,
176        )
177
178    def on_resize(self, width: int, height: int):
179        """
180        Resize window
181        Handle the user grabbing the edge and resizing the window.
182        """
183        super().on_resize(width, height)
184        self.camera_sprites.match_window()
185        self.camera_gui.match_window()
186
187
188def main():
189    """ Main function """
190    # Create a window class. This is what actually shows up on screen
191    window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
192
193    # Create and setup the GameView
194    game = GameView()
195    game.setup()
196
197    # Show GameView on screen
198    window.show_view(game)
199
200    # Start the arcade game loop
201    arcade.run()
202
203
204if __name__ == "__main__":
205    main()