Move with a Scrolling Screen

Screen shot of using a scrolling window
sprite_move_scrolling.py
  1"""
  2Use sprites to scroll around a large screen.
  3
  4Simple program to show basic sprite usage.
  5
  6Artwork from http://kenney.nl
  7
  8If Python and Arcade are installed, this example can be run from the command line with:
  9python -m arcade.examples.sprite_move_scrolling
 10"""
 11
 12import random
 13import arcade
 14import os
 15
 16SPRITE_SCALING = 0.5
 17
 18SCREEN_WIDTH = 800
 19SCREEN_HEIGHT = 600
 20SCREEN_TITLE = "Sprite Move with Scrolling Screen Example"
 21
 22# How many pixels to keep as a minimum margin between the character
 23# and the edge of the screen.
 24VIEWPORT_MARGIN = 40
 25
 26MOVEMENT_SPEED = 5
 27
 28
 29class MyGame(arcade.Window):
 30    """ Main application class. """
 31
 32    def __init__(self, width, height, title):
 33        """
 34        Initializer
 35        """
 36        super().__init__(width, height, title)
 37
 38        # Set the working directory (where we expect to find files) to the same
 39        # directory this .py file is in. You can leave this out of your own
 40        # code, but it is needed to easily run the examples using "python -m"
 41        # as mentioned at the top of this program.
 42        file_path = os.path.dirname(os.path.abspath(__file__))
 43        os.chdir(file_path)
 44
 45        # Sprite lists
 46        self.player_list = None
 47
 48        # Set up the player
 49        self.player_sprite = None
 50
 51        self.coin_list = None
 52        self.wall_list = None
 53
 54        self.physics_engine = None
 55
 56        # Used in scrolling
 57        self.view_bottom = 0
 58        self.view_left = 0
 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(":resources:images/animated_characters/female_person/femalePerson_idle.png", 0.4)
 69        self.player_sprite.center_x = 64
 70        self.player_sprite.center_y = 270
 71        self.player_list.append(self.player_sprite)
 72
 73        # -- Set up several columns of walls
 74        for x in range(200, 1650, 210):
 75            for y in range(0, 1000, 64):
 76                # Randomly skip a box so the player can find a way through
 77                if random.randrange(5) > 0:
 78                    wall = arcade.Sprite(":resources:images/tiles/boxCrate_double.png", SPRITE_SCALING)
 79                    wall.center_x = x
 80                    wall.center_y = y
 81                    self.wall_list.append(wall)
 82
 83        self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)
 84
 85        # Set the background color
 86        arcade.set_background_color(arcade.color.AMAZON)
 87
 88        # Set the viewport boundaries
 89        # These numbers set where we have 'scrolled' to.
 90        self.view_left = 0
 91        self.view_bottom = 0
 92
 93    def on_draw(self):
 94        """
 95        Render the screen.
 96        """
 97
 98        # This command has to happen before we start drawing
 99        arcade.start_render()
100
101        # Draw all the sprites.
102        self.wall_list.draw()
103        self.player_list.draw()
104
105    def on_key_press(self, key, modifiers):
106        """Called whenever a key is pressed. """
107
108        if key == arcade.key.UP:
109            self.player_sprite.change_y = MOVEMENT_SPEED
110        elif key == arcade.key.DOWN:
111            self.player_sprite.change_y = -MOVEMENT_SPEED
112        elif key == arcade.key.LEFT:
113            self.player_sprite.change_x = -MOVEMENT_SPEED
114        elif key == arcade.key.RIGHT:
115            self.player_sprite.change_x = 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.UP or key == arcade.key.DOWN:
121            self.player_sprite.change_y = 0
122        elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
123            self.player_sprite.change_x = 0
124
125    def on_update(self, delta_time):
126        """ Movement and game logic """
127
128        # Call update on all sprites (The sprites don't do much in this
129        # example though.)
130        self.physics_engine.update()
131
132        # --- Manage Scrolling ---
133
134        # Keep track of if we changed the boundary. We don't want to call the
135        # set_viewport command if we didn't change the view port.
136        changed = False
137
138        # Scroll left
139        left_boundary = self.view_left + VIEWPORT_MARGIN
140        if self.player_sprite.left < left_boundary:
141            self.view_left -= left_boundary - self.player_sprite.left
142            changed = True
143
144        # Scroll right
145        right_boundary = self.view_left + SCREEN_WIDTH - VIEWPORT_MARGIN
146        if self.player_sprite.right > right_boundary:
147            self.view_left += self.player_sprite.right - right_boundary
148            changed = True
149
150        # Scroll up
151        top_boundary = self.view_bottom + SCREEN_HEIGHT - VIEWPORT_MARGIN
152        if self.player_sprite.top > top_boundary:
153            self.view_bottom += self.player_sprite.top - top_boundary
154            changed = True
155
156        # Scroll down
157        bottom_boundary = self.view_bottom + VIEWPORT_MARGIN
158        if self.player_sprite.bottom < bottom_boundary:
159            self.view_bottom -= bottom_boundary - self.player_sprite.bottom
160            changed = True
161
162        # Make sure our boundaries are integer values. While the view port does
163        # support floating point numbers, for this application we want every pixel
164        # in the view port to map directly onto a pixel on the screen. We don't want
165        # any rounding errors.
166        self.view_left = int(self.view_left)
167        self.view_bottom = int(self.view_bottom)
168
169        # If we changed the boundary values, update the view port to match
170        if changed:
171            arcade.set_viewport(self.view_left,
172                                SCREEN_WIDTH + self.view_left,
173                                self.view_bottom,
174                                SCREEN_HEIGHT + self.view_bottom)
175
176
177def main():
178    """ Main method """
179    window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
180    window.setup()
181    arcade.run()
182
183
184if __name__ == "__main__":
185    main()