Step 13 - More Types of Layers
For this example, we’ll switch to a different built-in map that has more layers we can do things with.
In our setup function, load this map instead of the one from Chapter 12:
self.tile_map = arcade.load_tilemap(":resources:tiled_maps/map2_level_1.json", scaling=TILE_SCALING, layer_options=layer_options)
You can run this and check out the map we will be working with this chapter. You’ll notice in addition to the normal platforms and coins we’ve had. We now have some extra signs and decoration objects, as well as a pit of lava.
Back in chapter 6 we made use of our setup
function to reset the game. Let’s go ahead and use that
system here to reset the game when the player touches the lava pit. You can remove the section for resetting
when the Escape key is pressed if you want, or you can leave it in place. We can also play a game over sound
when this happens.
Let’s first add a new sound to our __init__
function for this:
self.gameover_sound = arcade.load_sound(":resources:sounds/gameover1.wav")
In order to do this, we’ll add this code in our on_update
function:
if arcade.check_for_collision_with_list(
self.player_sprite, self.scene["Don't Touch"]
):
arcade.play_sound(self.gameover_sound)
self.setup()
The map we are using here has some extra layers in it we haven’t used yet. In the code above we made use of
the Don't Touch
to reset the game when the player touches it. In this section we will make use of two
other layers in our new map, Background
and Foreground
.
We will use these layers as a way to separate objects that should be drawn in front of our player, and objects
that should be drawn behind the player. In our setup
function, before we create the player sprite, add this code.
self.scene.add_sprite_list_after("Player", "Foreground")
This code will cause our player spritelist to be inserted at a specific point in the Scene. Causing spritelists which are in front of it to be drawn before it, and ones behind it to be drawn after. By doing this we can make objects appear to be in front of or behind our player like the images below:


Source Code
1"""
2Platformer Game
3
4python -m arcade.examples.platform_tutorial.13_more_layers
5"""
6import arcade
7
8# Constants
9WINDOW_WIDTH = 1280
10WINDOW_HEIGHT = 720
11WINDOW_TITLE = "Platformer"
12
13# Constants used to scale our sprites from their original size
14TILE_SCALING = 0.5
15COIN_SCALING = 0.5
16
17# Movement speed of player, in pixels per frame
18PLAYER_MOVEMENT_SPEED = 5
19GRAVITY = 1
20PLAYER_JUMP_SPEED = 20
21
22
23class GameView(arcade.Window):
24 """
25 Main application class.
26 """
27
28 def __init__(self):
29
30 # Call the parent class and set up the window
31 super().__init__(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
32
33 # Variable to hold our texture for our player
34 self.player_texture = None
35
36 # Separate variable that holds the player sprite
37 self.player_sprite = None
38
39 # Variable to hold our Tiled Map
40 self.tile_map = None
41
42 # Replacing all of our SpriteLists with a Scene variable
43 self.scene = None
44
45 # A variable to store our camera object
46 self.camera = None
47
48 # A variable to store our gui camera object
49 self.gui_camera = None
50
51 # This variable will store our score as an integer.
52 self.score = 0
53
54 # This variable will store the text for score that we will draw to the screen.
55 self.score_text = None
56
57 # Load sounds
58 self.collect_coin_sound = arcade.load_sound(":resources:sounds/coin1.wav")
59 self.jump_sound = arcade.load_sound(":resources:sounds/jump1.wav")
60 self.gameover_sound = arcade.load_sound(":resources:sounds/gameover1.wav")
61
62 def setup(self):
63 """Set up the game here. Call this function to restart the game."""
64 layer_options = {
65 "Platforms": {
66 "use_spatial_hash": True
67 }
68 }
69
70 # Load our TileMap
71 self.tile_map = arcade.load_tilemap(
72 ":resources:tiled_maps/map2_level_1.json",
73 scaling=TILE_SCALING,
74 layer_options=layer_options,
75 )
76
77 # Create our Scene Based on the TileMap
78 self.scene = arcade.Scene.from_tilemap(self.tile_map)
79
80 self.player_texture = arcade.load_texture(
81 ":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"
82 )
83
84 # Add Player Spritelist before "Foreground" layer. This will make the foreground
85 # be drawn after the player, making it appear to be in front of the Player.
86 # Setting before using scene.add_sprite allows us to define where the SpriteList
87 # will be in the draw order. If we just use add_sprite, it will be appended to the
88 # end of the order.
89 self.scene.add_sprite_list_after("Player", "Foreground")
90
91 self.player_sprite = arcade.Sprite(self.player_texture)
92 self.player_sprite.center_x = 128
93 self.player_sprite.center_y = 128
94 self.scene.add_sprite("Player", self.player_sprite)
95
96 # Create a Platformer Physics Engine, this will handle moving our
97 # player as well as collisions between the player sprite and
98 # whatever SpriteList we specify for the walls.
99 # It is important to supply static to the walls parameter. There is a
100 # platforms parameter that is intended for moving platforms.
101 # If a platform is supposed to move, and is added to the walls list,
102 # it will not be moved.
103 self.physics_engine = arcade.PhysicsEnginePlatformer(
104 self.player_sprite, walls=self.scene["Platforms"], gravity_constant=GRAVITY
105 )
106
107 # Initialize our camera, setting a viewport the size of our window.
108 self.camera = arcade.camera.Camera2D()
109
110 # Initialize our gui camera, initial settings are the same as our world camera.
111 self.gui_camera = arcade.camera.Camera2D()
112
113 # Reset our score to 0
114 self.score = 0
115
116 # Initialize our arcade.Text object for score
117 self.score_text = arcade.Text(f"Score: {self.score}", x=0, y=5)
118
119 self.background_color = arcade.csscolor.CORNFLOWER_BLUE
120
121 def on_draw(self):
122 """Render the screen."""
123
124 # Clear the screen to the background color
125 self.clear()
126
127 # Activate our camera before drawing
128 self.camera.use()
129
130 # Draw our Scene
131 self.scene.draw()
132
133 # Activate our GUI camera
134 self.gui_camera.use()
135
136 # Draw our Score
137 self.score_text.draw()
138
139 def on_update(self, delta_time):
140 """Movement and Game Logic"""
141
142 # Move the player using our physics engine
143 self.physics_engine.update()
144
145 # See if we hit any coins
146 coin_hit_list = arcade.check_for_collision_with_list(
147 self.player_sprite, self.scene["Coins"]
148 )
149
150 # Loop through each coin we hit (if any) and remove it
151 for coin in coin_hit_list:
152 # Remove the coin
153 coin.remove_from_sprite_lists()
154 arcade.play_sound(self.collect_coin_sound)
155 self.score += 75
156 self.score_text.text = f"Score: {self.score}"
157
158 if arcade.check_for_collision_with_list(
159 self.player_sprite, self.scene["Don't Touch"]
160 ):
161 arcade.play_sound(self.gameover_sound)
162 self.setup()
163
164 # Center our camera on the player
165 self.camera.position = self.player_sprite.position
166
167 def on_key_press(self, key, modifiers):
168 """Called whenever a key is pressed."""
169
170 if key == arcade.key.ESCAPE:
171 self.setup()
172
173 if key == arcade.key.UP or key == arcade.key.W:
174 if self.physics_engine.can_jump():
175 self.player_sprite.change_y = PLAYER_JUMP_SPEED
176 arcade.play_sound(self.jump_sound)
177
178 if key == arcade.key.LEFT or key == arcade.key.A:
179 self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
180 elif key == arcade.key.RIGHT or key == arcade.key.D:
181 self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
182
183 def on_key_release(self, key, modifiers):
184 """Called whenever a key is released."""
185
186 if key == arcade.key.LEFT or key == arcade.key.A:
187 self.player_sprite.change_x = 0
188 elif key == arcade.key.RIGHT or key == arcade.key.D:
189 self.player_sprite.change_x = 0
190
191
192def main():
193 """Main function"""
194 window = GameView()
195 window.setup()
196 arcade.run()
197
198
199if __name__ == "__main__":
200 main()