# Step 14 - Multiple Levels#

Now we will make it so that our game has multiple levels. For now we will just have two levels, but this technique can be easily expanded to include more.

To start off, create two new variables in the `__init__` function to represent the position that marks the end of the map, and what level we should be loading.

```# Where is the right edge of the map?
self.end_of_map = 0

self.level = 1
```

Next in the `setup` function we will change the map loading call to use an f-string to load a map file depending on the level variable we created.

```# Load our TileMap
```

Again in the setup function, we will calculate where the edge of the currently loaded map is, in pixels. To do this we get the width of the map, which is represented in number of tiles, and multiply it by the tile width. We also need to consider the scaling of the tiles, because we are measuring this in pixels.

```# Calculate the right edge of the map in pixels
self.end_of_map = (self.tile_map.width * self.tile_map.tile_width) * self.tile_map.scaling
```

Now in the `on_update` function, we will add a block to check the player position against the end of the map value. We will do this right before the `center_camera_to_player` function call at the end. This will increment our current level, and leverage the `setup` function in order to re-load the game with the new level.

```# Check if the player got to the end of the level
if self.player_sprite.center_x >= self.end_of_map:
# Advance to the next level
self.level += 1

# Reload game with new level
self.setup()
```

If you run the game at this point, you will be able to reach the end of the first level and have the next level load and play through it. We have two problems at this point, did you notice them? The first problem is that the player’s score resets in between levels, maybe you want this to happen in your game, but we will fix it here so that when switching levels we don’t reset the score.

To do this, first add a new variable to the `__init__` function which will serve as a trigger to know if the score should be reset or not. We want to be able to reset it when the player loses, so this trigger will help us only reset the score when we want to.

```# Should we reset the score?
self.reset_score = True
```

Now in the `setup` function we can replace the score reset with this block of code. We change the `reset_score` variable back to True after resetting the score, because the default in our game should be to reset it, and we only turn off the reset when we want it off.

```# Reset the score if we should
if self.reset_score:
self.score = 0
self.reset_score = True
```

Finally, in the section of `on_update` that we advance the level, we can add this line to turn off the score reset

```# Turn off score reset when advancing level
self.reset_score = False
```

Now the player’s score will persist between levels, but we still have one more problem. If you reach the end of the second level, the game crashes! This is because we only actually have two levels available, but we are still trying to advance the level to 3 when we hit the end of level 2.

There’s a few ways this can be handled, one way is to simply make more levels. Eventually you have to have a final level though, so this probably isn’t the best solution. As an exercise, see if you can find a way to gracefully handle the final level. You could display an end screen, or restart the game from the beginning, or anything you want.

## Source Code#

Moving the enemies#
```  1"""
2Platformer Game
3
5"""
7
8# Constants
9SCREEN_WIDTH = 800
10SCREEN_HEIGHT = 600
11SCREEN_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
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__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_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        # Where is the right edge of the map?
58        self.end_of_map = 0
59
60        # Level number to load
61        self.level = 1
62
63        # Should we reset the score?
64        self.reset_score = True
65
70
71    def setup(self):
72        """Set up the game here. Call this function to restart the game."""
73        layer_options = {
74            "Platforms": {
75                "use_spatial_hash": True
76            }
77        }
78
81
82        # Create our Scene Based on the TileMap
84
86
87        # Add Player Spritelist before "Foreground" layer. This will make the foreground
88        # be drawn after the player, making it appear to be in front of the Player.
89        # Setting before using scene.add_sprite allows us to define where the SpriteList
90        # will be in the draw order. If we just use add_sprite, it will be appended to the
91        # end of the order.
93
95        self.player_sprite.center_x = 128
96        self.player_sprite.center_y = 128
98
99        # Create a Platformer Physics Engine, this will handle moving our
100        # player as well as collisions between the player sprite and
101        # whatever SpriteList we specify for the walls.
102        # It is important to supply static to the walls parameter. There is a
103        # platforms parameter that is intended for moving platforms.
104        # If a platform is supposed to move, and is added to the walls list,
105        # it will not be moved.
107            self.player_sprite, walls=self.scene["Platforms"], gravity_constant=GRAVITY
108        )
109
110        # Initialize our camera, setting a viewport the size of our window.
111        self.camera = arcade.SimpleCamera(viewport=(0, 0, self.width, self.height))
112
113        # Initialize our gui camera, initial settings are the same as our world camera.
114        self.gui_camera = arcade.SimpleCamera(viewport=(0, 0, self.width, self.height))
115
116        # Reset the score if we should
117        if self.reset_score:
118            self.score = 0
119        self.reset_score = True
120
121        # Initialize our arcade.Text object for score
122        self.score_text = arcade.Text(f"Score: {self.score}", start_x = 0, start_y = 5)
123
125
126        # Calculate the right edge of the map in pixels
127        self.end_of_map = (self.tile_map.width * self.tile_map.tile_width) * self.tile_map.scaling
128        print(self.end_of_map)
129
130    def on_draw(self):
131        """Render the screen."""
132
133        # Clear the screen to the background color
134        self.clear()
135
136        # Activate our camera before drawing
137        self.camera.use()
138
139        # Draw our Scene
140        self.scene.draw()
141
142        # Activate our GUI camera
143        self.gui_camera.use()
144
145        # Draw our Score
146        self.score_text.draw()
147
148    def on_update(self, delta_time):
149        """Movement and Game Logic"""
150
151        # Move the player using our physics engine
152        self.physics_engine.update()
153
154        # See if we hit any coins
156            self.player_sprite, self.scene["Coins"]
157        )
158
159        # Loop through each coin we hit (if any) and remove it
160        for coin in coin_hit_list:
161            # Remove the coin
162            coin.remove_from_sprite_lists()
164            self.score += 75
165            self.score_text.text = f"Score: {self.score}"
166
168            self.player_sprite, self.scene["Don't Touch"]
169        ):
171            self.setup()
172
173        # Check if the player got to the end of the level
174        if self.player_sprite.center_x >= self.end_of_map:
175            # Advance to the next level
176            self.level += 1
177
178            # Turn off score reset when advancing level
179            self.reset_score = False
180
181            # Reload game with new level
182            self.setup()
183
184        # Center our camera on the player
185        self.camera.center(self.player_sprite.position)
186
187    def on_key_press(self, key, modifiers):
188        """Called whenever a key is pressed."""
189
191            self.setup()
192
194            if self.physics_engine.can_jump():
195                self.player_sprite.change_y = PLAYER_JUMP_SPEED
197
199            self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
201            self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
202
203    def on_key_release(self, key, modifiers):
204        """Called whenever a key is released."""
205
207            self.player_sprite.change_x = 0