1"""
2Load a Tiled map file with Levels
3
4Artwork from: http://kenney.nl
5Tiled available from: http://www.mapeditor.org/
6
7If Python and Arcade are installed, this example can be run from the command line with:
8python -m arcade.examples.sprite_tiled_map_with_levels
9"""
10
11import arcade
12import os
13import time
14
15TILE_SPRITE_SCALING = 0.5
16PLAYER_SCALING = 0.6
17
18SCREEN_WIDTH = 800
19SCREEN_HEIGHT = 600
20SCREEN_TITLE = "Sprite Tiled Map with Levels Example"
21SPRITE_PIXEL_SIZE = 128
22GRID_PIXEL_SIZE = (SPRITE_PIXEL_SIZE * TILE_SPRITE_SCALING)
23
24# How many pixels to keep as a minimum margin between the character
25# and the edge of the screen.
26VIEWPORT_MARGIN_TOP = 60
27VIEWPORT_MARGIN_BOTTOM = 60
28VIEWPORT_RIGHT_MARGIN = 270
29VIEWPORT_LEFT_MARGIN = 270
30
31# Physics
32MOVEMENT_SPEED = 5
33JUMP_SPEED = 23
34GRAVITY = 1.1
35
36
37class MyGame(arcade.Window):
38 """ Main application class. """
39
40 def __init__(self):
41 """
42 Initializer
43 """
44 super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
45
46 # Set the working directory (where we expect to find files) to the same
47 # directory this .py file is in. You can leave this out of your own
48 # code, but it is needed to easily run the examples using "python -m"
49 # as mentioned at the top of this program.
50 file_path = os.path.dirname(os.path.abspath(__file__))
51 os.chdir(file_path)
52
53 # Sprite lists
54 self.wall_list = None
55 self.player_list = None
56 self.coin_list = None
57
58 # Set up the player
59 self.score = 0
60 self.player_sprite = None
61
62 self.physics_engine = None
63 self.view_left = 0
64 self.view_bottom = 0
65 self.end_of_map = 0
66 self.game_over = False
67 self.last_time = None
68 self.frame_count = 0
69 self.fps_message = None
70
71 self.level = 1
72 self.max_level = 2
73
74 def setup(self):
75 """ Set up the game and initialize the variables. """
76
77 # Sprite lists
78 self.player_list = arcade.SpriteList()
79 self.coin_list = arcade.SpriteList()
80
81 # Set up the player
82 self.player_sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png",
83 PLAYER_SCALING)
84
85 # Starting position of the player
86 self.player_sprite.center_x = 128
87 self.player_sprite.center_y = 64
88 self.player_list.append(self.player_sprite)
89
90 self.load_level(self.level)
91
92 self.game_over = False
93
94 def load_level(self, level):
95 # Read in the tiled map
96 my_map = arcade.tilemap.read_tmx(f":resources:tmx_maps/level_{level}.tmx")
97
98 # --- Walls ---
99
100 # Calculate the right edge of the my_map in pixels
101 self.end_of_map = my_map.map_size.width * GRID_PIXEL_SIZE
102
103 # Grab the layer of items we can't move through
104 self.wall_list = arcade.tilemap.process_layer(my_map,
105 'Platforms',
106 TILE_SPRITE_SCALING,
107 use_spatial_hash=True)
108
109 self.physics_engine = arcade.PhysicsEnginePlatformer(self.player_sprite,
110 self.wall_list,
111 gravity_constant=GRAVITY)
112
113 # --- Other stuff
114 # Set the background color
115 if my_map.background_color:
116 arcade.set_background_color(my_map.background_color)
117
118 # Set the view port boundaries
119 # These numbers set where we have 'scrolled' to.
120 self.view_left = 0
121 self.view_bottom = 0
122
123 def on_draw(self):
124 """
125 Render the screen.
126 """
127
128 self.frame_count += 1
129
130 # This command has to happen before we start drawing
131 arcade.start_render()
132
133 # Draw all the sprites.
134 self.player_list.draw()
135 self.wall_list.draw()
136 self.coin_list.draw()
137
138 if self.last_time and self.frame_count % 60 == 0:
139 fps = 1.0 / (time.time() - self.last_time) * 60
140 self.fps_message = f"FPS: {fps:5.0f}"
141
142 if self.fps_message:
143 arcade.draw_text(self.fps_message, self.view_left + 10, self.view_bottom + 40, arcade.color.BLACK, 14)
144
145 if self.frame_count % 60 == 0:
146 self.last_time = time.time()
147
148 # Put the text on the screen.
149 # Adjust the text position based on the view port so that we don't
150 # scroll the text too.
151 distance = self.player_sprite.right
152 output = f"Distance: {distance:.0f}"
153 arcade.draw_text(output, self.view_left + 10, self.view_bottom + 20, arcade.color.BLACK, 14)
154
155 if self.game_over:
156 arcade.draw_text("Game Over", self.view_left + 200, self.view_bottom + 200, arcade.color.BLACK, 30)
157
158 def on_key_press(self, key, modifiers):
159 """
160 Called whenever the mouse moves.
161 """
162 if key == arcade.key.UP:
163 if self.physics_engine.can_jump():
164 self.player_sprite.change_y = JUMP_SPEED
165 elif key == arcade.key.LEFT:
166 self.player_sprite.change_x = -MOVEMENT_SPEED
167 elif key == arcade.key.RIGHT:
168 self.player_sprite.change_x = MOVEMENT_SPEED
169
170 def on_key_release(self, key, modifiers):
171 """
172 Called when the user presses a mouse button.
173 """
174 if key == arcade.key.LEFT or key == arcade.key.RIGHT:
175 self.player_sprite.change_x = 0
176
177 def on_update(self, delta_time):
178 """ Movement and game logic """
179
180 if self.player_sprite.right >= self.end_of_map:
181 if self.level < self.max_level:
182 self.level += 1
183 self.load_level(self.level)
184 self.player_sprite.center_x = 128
185 self.player_sprite.center_y = 64
186 self.player_sprite.change_x = 0
187 self.player_sprite.change_y = 0
188 else:
189 self.game_over = True
190
191 # Call update on all sprites (The sprites don't do much in this
192 # example though.)
193 if not self.game_over:
194 self.physics_engine.update()
195
196 coins_hit = arcade.check_for_collision_with_list(self.player_sprite, self.coin_list)
197 for coin in coins_hit:
198 coin.remove_from_sprite_lists()
199 self.score += 1
200
201 # --- Manage Scrolling ---
202
203 # Track if we need to change the view port
204
205 changed = False
206
207 # Scroll left
208 left_bndry = self.view_left + VIEWPORT_LEFT_MARGIN
209 if self.player_sprite.left < left_bndry:
210 self.view_left -= left_bndry - self.player_sprite.left
211 changed = True
212
213 # Scroll right
214 right_bndry = self.view_left + SCREEN_WIDTH - VIEWPORT_RIGHT_MARGIN
215 if self.player_sprite.right > right_bndry:
216 self.view_left += self.player_sprite.right - right_bndry
217 changed = True
218
219 # Scroll up
220 top_bndry = self.view_bottom + SCREEN_HEIGHT - VIEWPORT_MARGIN_TOP
221 if self.player_sprite.top > top_bndry:
222 self.view_bottom += self.player_sprite.top - top_bndry
223 changed = True
224
225 # Scroll down
226 bottom_bndry = self.view_bottom + VIEWPORT_MARGIN_BOTTOM
227 if self.player_sprite.bottom < bottom_bndry:
228 self.view_bottom -= bottom_bndry - self.player_sprite.bottom
229 changed = True
230
231 # If we need to scroll, go ahead and do it.
232 if changed:
233 self.view_left = int(self.view_left)
234 self.view_bottom = int(self.view_bottom)
235 arcade.set_viewport(self.view_left,
236 SCREEN_WIDTH + self.view_left,
237 self.view_bottom,
238 SCREEN_HEIGHT + self.view_bottom)
239
240
241def main():
242 window = MyGame()
243 window.setup()
244 arcade.run()
245
246
247if __name__ == "__main__":
248 main()