Search code examples
javascriptphaser-frameworktile

Tilemap depth sorting by tile ID?


I have a top down game and I need the player to be rendered below the bottom walls, and above the top walls, and my solution would be to set the depth of individual tiles in the tilemap by the tile ID. I can't use anything involving tiled, because my game will be procedurally generated. Maybe something similar to this:

this.wallLayer.forEachTile((tile)=>{ 
    if(tile.id === 1){
       tile.setDepth(1)
    }
    if(tile.id === 2){
       tile.setDepth(3)
    }
})

if there is a similar method I could use, it would be great if someone could point me in the right direction. Thanks!


Solution

  • I'm not sure if this is the best solution, but i would create two maps and place one over the other.

    1. first map + layer is incharge for collision and everything the player should cover. Set a lower depth than the player.
    2. second map + layer is incharge to be infront of the layer.
      Using the function replaceByIndex, to remove indices that should not covered the player. (link to documentation) And setting a higher depth than the player

    Here a short Demo showcasing this:
    (use cursor-keys to move the player)
    Red-Tiles should cover the player, blue tiles should be coverd by the player.

    document.body.style = 'margin:0;';
    
    var config = {
        type: Phaser.AUTO,
        width: 536 /8,
        height: 34,
        zoom: 6,
        physics: {
            default: 'arcade',
            arcade: {            
                gravity:{ y: 0 },
                debug: false
            }
        },
        scene: {
            create,
            update
        },
        banner: false
    }; 
    
    function create () {
    
        let graphics  = this.make.graphics();
        graphics.fillStyle(0x00ff00);
        graphics.fillRect(8, 0, 8, 8);
        graphics.fillStyle(0xff0000);
        graphics.fillRect(16, 0, 8, 8);
        graphics.fillStyle(0x0000ff);
        graphics.fillRect(24, 0, 8, 8);
        graphics.generateTexture('tiles', 8*4, 8);
    
        var level = [
          [1,1,1,1,1],
          [1,0,3,0,1],
          [1,0,0,0,1],
          [1,2,2,2,1],
        ]
    
        // Map for the first level
        var map = this.make.tilemap({ data: level, tileWidth: 8, tileHeight: 8 });
        var tiles = map.addTilesetImage('tiles');
        var layer = map.createLayer(0, tiles, 0, 0);
        layer.setCollision(1);
        
    
        var map2 = this.make.tilemap({ data: level, tileWidth: 8, tileHeight: 8 });
        var layer2 = map2.createLayer(0, tiles, 0, 0);
        
        layer2.setDepth(10);
        
        //remove tile that should not overlap
        map2.replaceByIndex(3, -1);
        
        this.player = this.add.circle(16,16,4, 0xffffff)
          .setDepth(2);
        
        this.physics.add.existing(this.player);
        
        // Just setup collision with the first layer
        this.physics.add.collider(layer, this.player);
        
        this.keys = this.input.keyboard.createCursorKeys();
    }
    
    function update(){
      let speed = 20;
      
      this.player.body.setVelocity(0)
      if(this.keys.up.isDown){
        this.player.body.setVelocityY(-speed)
      }
      
      if(this.keys.down.isDown){
        this.player.body.setVelocityY(speed)
      }
      
      if(this.keys.left.isDown){
        this.player.body.setVelocityX(-speed)
      }
      
      if(this.keys.right.isDown){
        this.player.body.setVelocityX(speed)
      }
    }
    
    new Phaser.Game(config);
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>