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()