1"""
2Platformer Game
3"""
4import arcade
5
6# Constants
7SCREEN_WIDTH = 1000
8SCREEN_HEIGHT = 650
9SCREEN_TITLE = "Platformer"
10
11# Constants used to scale our sprites from their original size
12CHARACTER_SCALING = 1
13TILE_SCALING = 0.5
14COIN_SCALING = 0.5
15SPRITE_PIXEL_SIZE = 128
16GRID_PIXEL_SIZE = (SPRITE_PIXEL_SIZE * TILE_SCALING)
17
18# Movement speed of player, in pixels per frame
19PLAYER_MOVEMENT_SPEED = 10
20GRAVITY = 1
21PLAYER_JUMP_SPEED = 20
22
23# How many pixels to keep as a minimum margin between the character
24# and the edge of the screen.
25LEFT_VIEWPORT_MARGIN = 250
26RIGHT_VIEWPORT_MARGIN = 250
27BOTTOM_VIEWPORT_MARGIN = 100
28TOP_VIEWPORT_MARGIN = 100
29
30
31class MyGame(arcade.Window):
32 """
33 Main application class.
34 """
35
36 def __init__(self):
37
38 # Call the parent class and set up the window
39 super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
40
41 # These are 'lists' that keep track of our sprites. Each sprite should
42 # go into a list.
43 self.coin_list = None
44 self.wall_list = None
45 self.player_list = None
46
47 # Separate variable that holds the player sprite
48 self.player_sprite = None
49
50 # Our physics engine
51 self.physics_engine = None
52
53 # Used to keep track of our scrolling
54 self.view_bottom = 0
55 self.view_left = 0
56
57 # Keep track of the score
58 self.score = 0
59
60 # Load sounds
61 self.collect_coin_sound = arcade.load_sound(":resources:sounds/coin1.wav")
62 self.jump_sound = arcade.load_sound(":resources:sounds/jump1.wav")
63
64 arcade.set_background_color(arcade.csscolor.CORNFLOWER_BLUE)
65
66 def setup(self):
67 """ Set up the game here. Call this function to restart the game. """
68
69 # Used to keep track of our scrolling
70 self.view_bottom = 0
71 self.view_left = 0
72
73 # Keep track of the score
74 self.score = 0
75
76 # Create the Sprite lists
77 self.player_list = arcade.SpriteList()
78 self.wall_list = arcade.SpriteList()
79 self.coin_list = arcade.SpriteList()
80
81 # Set up the player, specifically placing it at these coordinates.
82 image_source = ":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"
83 self.player_sprite = arcade.Sprite(image_source, CHARACTER_SCALING)
84 self.player_sprite.center_x = 128
85 self.player_sprite.center_y = 128
86 self.player_list.append(self.player_sprite)
87
88 # --- Load in a map from the tiled editor ---
89
90 # Name of map file to load
91 map_name = ":resources:tmx_maps/map.tmx"
92 # Name of the layer in the file that has our platforms/walls
93 platforms_layer_name = 'Platforms'
94 # Name of the layer that has items for pick-up
95 coins_layer_name = 'Coins'
96
97 # Read in the tiled map
98 my_map = arcade.tilemap.read_tmx(map_name)
99
100 # -- Platforms
101 self.wall_list = arcade.tilemap.process_layer(map_object=my_map,
102 layer_name=platforms_layer_name,
103 scaling=TILE_SCALING,
104 use_spatial_hash=True)
105
106 # -- Coins
107 self.coin_list = arcade.tilemap.process_layer(my_map, coins_layer_name, TILE_SCALING)
108
109 # --- Other stuff
110 # Set the background color
111 if my_map.background_color:
112 arcade.set_background_color(my_map.background_color)
113
114 # Create the 'physics engine'
115 self.physics_engine = arcade.PhysicsEnginePlatformer(self.player_sprite,
116 self.wall_list,
117 GRAVITY)
118
119 def on_draw(self):
120 """ Render the screen. """
121
122 # Clear the screen to the background color
123 arcade.start_render()
124
125 # Draw our sprites
126 self.wall_list.draw()
127 self.coin_list.draw()
128 self.player_list.draw()
129
130 # Draw our score on the screen, scrolling it with the viewport
131 score_text = f"Score: {self.score}"
132 arcade.draw_text(score_text, 10 + self.view_left, 10 + self.view_bottom,
133 arcade.csscolor.WHITE, 18)
134
135 def on_key_press(self, key, modifiers):
136 """Called whenever a key is pressed. """
137
138 if key == arcade.key.UP or key == arcade.key.W:
139 if self.physics_engine.can_jump():
140 self.player_sprite.change_y = PLAYER_JUMP_SPEED
141 arcade.play_sound(self.jump_sound)
142 elif key == arcade.key.LEFT or key == arcade.key.A:
143 self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
144 elif key == arcade.key.RIGHT or key == arcade.key.D:
145 self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
146
147 def on_key_release(self, key, modifiers):
148 """Called when the user releases a key. """
149
150 if key == arcade.key.LEFT or key == arcade.key.A:
151 self.player_sprite.change_x = 0
152 elif key == arcade.key.RIGHT or key == arcade.key.D:
153 self.player_sprite.change_x = 0
154
155 def on_update(self, delta_time):
156 """ Movement and game logic """
157
158 # Move the player with the physics engine
159 self.physics_engine.update()
160
161 # See if we hit any coins
162 coin_hit_list = arcade.check_for_collision_with_list(self.player_sprite,
163 self.coin_list)
164
165 # Loop through each coin we hit (if any) and remove it
166 for coin in coin_hit_list:
167 # Remove the coin
168 coin.remove_from_sprite_lists()
169 # Play a sound
170 arcade.play_sound(self.collect_coin_sound)
171 # Add one to the score
172 self.score += 1
173
174 # --- Manage Scrolling ---
175
176 # Track if we need to change the viewport
177
178 changed = False
179
180 # Scroll left
181 left_boundary = self.view_left + LEFT_VIEWPORT_MARGIN
182 if self.player_sprite.left < left_boundary:
183 self.view_left -= left_boundary - self.player_sprite.left
184 changed = True
185
186 # Scroll right
187 right_boundary = self.view_left + SCREEN_WIDTH - RIGHT_VIEWPORT_MARGIN
188 if self.player_sprite.right > right_boundary:
189 self.view_left += self.player_sprite.right - right_boundary
190 changed = True
191
192 # Scroll up
193 top_boundary = self.view_bottom + SCREEN_HEIGHT - TOP_VIEWPORT_MARGIN
194 if self.player_sprite.top > top_boundary:
195 self.view_bottom += self.player_sprite.top - top_boundary
196 changed = True
197
198 # Scroll down
199 bottom_boundary = self.view_bottom + BOTTOM_VIEWPORT_MARGIN
200 if self.player_sprite.bottom < bottom_boundary:
201 self.view_bottom -= bottom_boundary - self.player_sprite.bottom
202 changed = True
203
204 if changed:
205 # Only scroll to integers. Otherwise we end up with pixels that
206 # don't line up on the screen
207 self.view_bottom = int(self.view_bottom)
208 self.view_left = int(self.view_left)
209
210 # Do the scrolling
211 arcade.set_viewport(self.view_left,
212 SCREEN_WIDTH + self.view_left,
213 self.view_bottom,
214 SCREEN_HEIGHT + self.view_bottom)
215
216
217def main():
218 """ Main method """
219 window = MyGame()
220 window.setup()
221 arcade.run()
222
223
224if __name__ == "__main__":
225 main()