pythonarcade

How do I use Object Layers from Tiled Maps using Python Arcade


I'm creating a basic game using Python Arcade and Tiled Map Editor. My problem is, I can't use the Object Layer in arcade in their built-in Physics Engine. I can see, after creating an instance of the tiled map the layers are separated into Tile Layers and Object Layers, but arcade.PhysicsEngineSimple() doesn't use the object layers. This means I can't have collisions into walls or set a starting position for my player and enemies.

I asked a similar question before: Unable to use Object Layer from a Tiled Map with Python Arcade, which involved creating a Tile Layer called "Walls" and using "use_spatial_hash": True, but after using the solution, I realized that this still only uses the Tile Layer and doesn't work for what I want. The collisions work, but it will be set to the size of the tile (In my case 64X64) but if I want a collision boundary that is thin and long then it won't work.

enter image description here

If anyone has any experience with handling Object Layers in Python Arcade, your help will be greatly appreciated.

It is very basic code at the moment, as I'm just learning arcade.

My code can be found here: Basic Dungeon Game

I am using arcade version 3.0.0dev32


Solution

  • There is no built-in functionality to support Object Layers in Arcade. So you need to write your own. For example you can use following approach:

    1. Read Object Layer data from tilemap
    2. Generate Sprite with the Object Layer coordinates
    3. Add Sprite to Walls Sprite list

    walls

    Below is your updated code:

    import arcade
    
    from game_sprites import Player
    
    SCALE = 3
    PLAYER_MOVEMENT_SPEED = 7
    
    
    class Game(arcade.Window):
        def __init__(self):
            super().__init__()
            self.camera = None
            self.tile_map = None
            map_name = "maps/dungeon.tmx"
            layer_options = {'Bricks': {'use_spatial_hash': True}}
            self.tile_map = arcade.load_tilemap(map_name, SCALE, layer_options)
            player_position = self.tile_map.object_lists["Sprite Positions"][0].properties
    
            # Get object layer
            points = self.tile_map.object_lists['Walls'][0].shape
            width = abs(points[0][0] - points[1][0])
            height = abs(points[0][1] - points[2][1])
            center_x = points[0][0] + width/2
            center_y = points[0][1] - height/2
            wall = arcade.SpriteSolidColor(width, height, center_x, center_y, arcade.color.RED)
    
            self.scene = arcade.Scene.from_tilemap(self.tile_map)
            walls = self.scene['Bricks']
            walls.append(wall)
    
            self.player = Player(center_x=player_position["X"]*SCALE, center_y=player_position["Y"]*SCALE, scale=1)
            self.player_list = arcade.SpriteList()
            self.player_list.append(self.player)
            self.physics_engine = arcade.PhysicsEngineSimple(self.player, walls=walls)
            self.camera_sprites = arcade.camera.Camera2D()
            self.left_pressed = False
            self.right_pressed = False
            self.up_pressed = False
            self.down_pressed = False
    
        def on_draw(self):
            self.clear()
            self.camera_sprites.use()
            self.scene.draw()
            self.player_list.draw()
    
        def on_update(self, delta_time):
            self.physics_engine.update()
            self.player.update_animation()
            self.player.change_x = 0
            self.player.change_y = 0
    
            # self.player.coll
    
            if self.up_pressed and not self.down_pressed:
                self.player.change_y = PLAYER_MOVEMENT_SPEED
            elif self.down_pressed and not self.up_pressed:
                self.player.change_y = -PLAYER_MOVEMENT_SPEED
            if self.left_pressed and not self.right_pressed:
                self.player.change_x = -PLAYER_MOVEMENT_SPEED
            elif self.right_pressed and not self.left_pressed:
                self.player.change_x = PLAYER_MOVEMENT_SPEED
    
            self.scroll_to_player()
    
        def on_key_press(self, key, modifiers):
    
            if key == arcade.key.UP:
                self.up_pressed = True
            elif key == arcade.key.DOWN:
                self.down_pressed = True
            elif key == arcade.key.LEFT:
                self.left_pressed = True
            elif key == arcade.key.RIGHT:
                self.right_pressed = True
    
        def on_key_release(self, key, modifiers):
    
            if key == arcade.key.UP:
                self.up_pressed = False
            elif key == arcade.key.DOWN:
                self.down_pressed = False
            elif key == arcade.key.LEFT:
                self.left_pressed = False
            elif key == arcade.key.RIGHT:
                self.right_pressed = False
    
        def scroll_to_player(self):
            position = (self.player.center_x, self.player.center_y)
            self.camera_sprites.position = arcade.math.lerp_2d(self.camera_sprites.position, position, 0.1)
    
    
    Game()
    arcade.run()