Work with levels and a tiled map

Screenshot of using a larger map created by the Tiled Map Editor
sprite_tiled_map_with_levels.py
  1"""
  2Load a Tiled map file with Levels
  3
  4Artwork from: https://kenney.nl
  5Tiled available from: https://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"""
 10import arcade
 11
 12TILE_SPRITE_SCALING = 0.5
 13PLAYER_SCALING = 0.6
 14
 15WINDOW_WIDTH = 1280
 16WINDOW_HEIGHT = 720
 17WINDOW_TITLE = "Sprite Tiled Map with Levels Example"
 18SPRITE_PIXEL_SIZE = 128
 19GRID_PIXEL_SIZE = SPRITE_PIXEL_SIZE * TILE_SPRITE_SCALING
 20CAMERA_PAN_SPEED = 0.15
 21
 22# Physics
 23MOVEMENT_SPEED = 5
 24JUMP_SPEED = 23
 25GRAVITY = 1.1
 26
 27
 28class GameView(arcade.View):
 29    """Main application class."""
 30
 31    def __init__(self):
 32        """
 33        Initializer
 34        """
 35        super().__init__()
 36
 37        # Tilemap Object
 38        self.tile_map = None
 39
 40        # Sprite lists
 41        self.player_list = None
 42
 43        # Set up the player
 44        self.score = 0
 45        self.player_sprite = None
 46
 47        self.physics_engine = None
 48        self.end_of_map = 0
 49        self.game_over = False
 50
 51        self.game_camera = None
 52        self.gui_camera = None
 53        self.camera_bounds = None
 54
 55        self.fps_text = None
 56        self.game_over_text = None
 57
 58        self.level = 1
 59        self.max_level = 2
 60
 61    def setup(self):
 62        """Set up the game and initialize the variables."""
 63
 64        # Sprite lists
 65        self.player_list = arcade.SpriteList()
 66
 67        # Set up the player
 68        self.player_sprite = arcade.Sprite(
 69            ":resources:images/animated_characters/female_person/femalePerson_idle.png",
 70            scale=PLAYER_SCALING,
 71        )
 72
 73        self.game_camera = arcade.camera.Camera2D()
 74        self.gui_camera = arcade.camera.Camera2D()
 75
 76        self.fps_text = arcade.Text('FPS:', 10, 10, arcade.color.BLACK, 14)
 77        self.game_over_text = arcade.Text(
 78            'GAME OVER',
 79            self.window.center_x,
 80            self.window.center_y,
 81            arcade.color.BLACK, 30,
 82            anchor_x='center',
 83            anchor_y='center'
 84        )
 85
 86        # Starting position of the player
 87        self.player_sprite.center_x = 128
 88        self.player_sprite.center_y = 64
 89        self.player_list.append(self.player_sprite)
 90
 91        self.load_level(self.level)
 92
 93        self.game_over = False
 94
 95    def load_level(self, level):
 96        # layer_options = {"Platforms": {"use_spatial_hash": True}}
 97
 98        # Read in the tiled map
 99        self.tile_map = arcade.load_tilemap(
100            f":resources:tiled_maps/level_{level}.json", scaling=TILE_SPRITE_SCALING
101        )
102
103        # --- Walls ---
104
105        # Calculate the right edge of the my_map in pixels
106        self.end_of_map = self.tile_map.width * GRID_PIXEL_SIZE
107
108        self.physics_engine = arcade.PhysicsEnginePlatformer(
109            self.player_sprite,
110            self.tile_map.sprite_lists["Platforms"],
111            gravity_constant=GRAVITY,
112        )
113
114        # --- Other stuff
115        # Set the background color
116        if self.tile_map.background_color:
117            self.window.background_color = self.tile_map.background_color
118
119        max_x = GRID_PIXEL_SIZE * self.tile_map.width
120        max_y = GRID_PIXEL_SIZE * self.tile_map.height
121        limit_y = max_y > self.window.height
122        self.camera_bounds = arcade.LRBT(
123            self.window.width / 2.0,
124            max_x - self.window.width / 2.0,
125            self.window.height / 2.0,
126            max_y - (self.window.height / 2.0 if limit_y else 0.0)
127        )
128
129        # Reset cam
130        self.game_camera.position = self.window.center
131
132    def on_draw(self):
133        """
134        Render the screen.
135        """
136        # This command has to happen before we start drawing
137        self.clear()
138
139        with self.game_camera.activate():
140            # Draw all the sprites.
141            self.tile_map.sprite_lists["Platforms"].draw()
142            self.player_list.draw()
143
144        with self.gui_camera.activate():
145            # Put the text on the screen.
146            # Adjust the text position based on the view port so that we don't
147            # scroll the text too.
148            output = f"FPS: {1/self.window.delta_time:.0f}"
149            arcade.draw_text(
150                output, 10, 20, arcade.color.BLACK, 14
151            )
152
153            if self.game_over:
154                self.game_over_text.position = self.window.center
155                self.game_over_text.draw()
156
157    def on_key_press(self, key, modifiers):
158        """
159        Called whenever the mouse moves.
160        """
161        if key == arcade.key.UP:
162            if self.physics_engine.can_jump():
163                self.player_sprite.change_y = JUMP_SPEED
164        elif key == arcade.key.LEFT:
165            self.player_sprite.change_x = -MOVEMENT_SPEED
166        elif key == arcade.key.RIGHT:
167            self.player_sprite.change_x = MOVEMENT_SPEED
168
169    def on_key_release(self, key, modifiers):
170        """
171        Called when the user presses a mouse button.
172        """
173        if key == arcade.key.LEFT or key == arcade.key.RIGHT:
174            self.player_sprite.change_x = 0
175
176    def on_update(self, delta_time):
177        """Movement and game logic"""
178
179        if self.player_sprite.right >= self.end_of_map:
180            if self.level < self.max_level:
181                self.level += 1
182                self.load_level(self.level)
183                self.player_sprite.center_x = 128
184                self.player_sprite.center_y = 64
185                self.player_sprite.change_x = 0
186                self.player_sprite.change_y = 0
187            else:
188                self.game_over = True
189
190        # Call update on all sprites (The sprites don't do much in this
191        # example though.)
192        if not self.game_over:
193            self.physics_engine.update()
194
195            # --- Manage Scrolling ---
196            self.game_camera.position = arcade.math.smerp_2d(
197                self.game_camera.position,
198                self.player_sprite.position,
199                delta_time,
200                CAMERA_PAN_SPEED
201            )
202            self.game_camera.position = arcade.camera.grips.constrain_xy(
203                self.game_camera.view_data,
204                self.camera_bounds
205            )
206
207
208def main():
209    window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
210    game = GameView()
211    game.setup()
212
213    window.show_view(game)
214    window.run()
215
216
217if __name__ == "__main__":
218    main()