Help with Tiled layer collision

Hi,

I’m using Tiled map to do a little platformer and I have issues about a collectable item (here coin).

The best I got was the item delete itself with the player colliding, but in fact the function is called at each new tile discovered of the layer.

var config = {
    type: Phaser.AUTO,
    width: 1200,
    height: 700,
    scene: {
        preload: preload,
        create: create,
        update: update
    },
    physics : {
        default : "arcade",
        arcade : {
            debug: true,
            gravity: { y: 1000 },
        }
    }
};

var game = new Phaser.Game(config);
var coinLayer;
var coinsCollected = 0;
var cooldown = 0;


function preload (){
    this.load.tilemapTiledJSON('map',"../JSON/big_head/test28274.json");

    this.load.image("tiles","../img/big_head/morning.png");
    //this.load.image("coin","../img/big_head/coin.png");
    this.load.atlas('player', '../img/big_head/player.png', '../JSON/big_head/player.json');

    //this.load.image('spike', '../img/big_head/spike.png');
    this.load.spritesheet('coin', '../img/big_head/coin.png', { frameWidth: 32, frameHeight: 32 });

}

function create (){
    
    this.cursors = this.input.keyboard.createCursorKeys();

    /********************************/
    /*                              */
    /* --  Création de la carte --  */
    /*                              */
    /********************************/
    
    const map = this.make.tilemap({ key: "map", tileWidth: 1400, tileHeight: 40});
    const tileset = map.addTilesetImage("morning_adventures_tileset_16x16","tiles");


    /************************************/
    /*                                  */
    /* --  Création des plateformes --  */
    /*                                  */
    /************************************/

    const platforms = map.createLayer('back', tileset, 0, 0);
    //platforms.setCollisionByExclusion(-1, true);
    platforms.setCollisionBetween(1, 60);

    /*************************************/
    /*                                   */
    /* --  Création des récupérables --  */
    /*                                   */
    /*************************************/

    var coinTiles = map.addTilesetImage('coin', 'coin');
    coinLayer = map.createLayer('items', coinTiles, 0, 0);


    /********************************/
    /*                              */
    /*  --  Création du perso   --  */
    /*                              */
    /********************************/ 

    this.player = this.physics.add.sprite(0, 0, 'player').setCollideWorldBounds(true);
    this.player.setScale(0.5);
    this.physics.add.collider(this.player, platforms);

    // PB TILEMAP
    coinLayer.setTileIndexCallback(61, hitCoin, this.player);
    //this.physics.add.overlap(this.player, coinLayer, hitCoin);

    /********************************/
    /*                              */
    /* --  Gestion de la caméra --  */
    /*                              */
    /********************************/

    this.cameras.main.setBounds(0, 0, 15400, 4000);
    this.physics.world.setBounds(0, 0, 15400, 4000);

    this.cameras.main.setZoom(1);

    this.cameras.main.startFollow(this.player, true, 0.08, 0.08);

    /********************************/
    /*                              */
    /*   --  Création du texte  --  */
    /*                              */
    /********************************/


    text = this.add.text(1, 1, '', {
        fontSize: '20px',
        fill: '#ffffff'
    });
    text.setScrollFactor(0);
    updateText();
   
    /********************************/
    /*                              */
    /*   --  Player animations  --  */
    /*                              */
    /********************************/


    this.anims.create({
        key: 'walk',
        frames: this.anims.generateFrameNames('player', { prefix: 'p1_walk', start: 1, end: 11, zeroPad: 2}),
        frameRate: 10,
    });
}

function update (time, delta)
{
    this.player.setVelocityX(0);

    if (this.cursors.left.isDown)
    {
        this.player.setVelocityX(-500);
        this.player.flipX = true;
        this.player.anims.play('walk', true); // play walk animation

    }
    else if (this.cursors.right.isDown)
    {
        this.player.setVelocityX(500);
        this.player.flipX = false;
        this.player.anims.play('walk', true); // play walk animation
    }

    if ((this.cursors.up.isDown || this.cursors.space.isDown) && this.player.body.onFloor() || (this.player.body.onWall() && (this.cursors.up.isDown || this.cursors.space.isDown)))
    {    
        if(cooldown == 0 || time - cooldown >= 600){
            this.player.setVelocityY(-640);
                cooldown = time;
        }
    }

    if (this.cursors.left.isDown && this.player.x > 0)
    {
        //this.player.setAngle(-90);
        this.player.x -= 2.5;
    }
    else if (this.cursors.right.isDown && this.player.x < 3392)
    {
        //this.player.setAngle(90);
        this.player.x += 2.5;
    }
}

function hitCoin (sprite, tile)
{
    coinLayer.removeTileAt(tile.x, tile.y);
    coinsCollected += 1;

    updateText();

    console.log("coucou")

    return true;
}

function updateText ()
{
    text.setText(
        '\nCoins collected: ' + coinsCollected
    );
}

Does somebody knows how to do ?

Thanks !

:wave:

Use this.physics.add.collider(this.player, coinLayer, hitCoin);

Hi !
I’ve been trying it, but it triggers the function each time a player “collides” with a new tile of coinLayer.
Like, if I run straight and there are 9 tiles of the layer (even if 0 coins), hitcoin function is printing 9.

And with this line it does nothing.
Hitcoin is never called (via console.log)

You can try to loop tilemap or filter tilemap and add collision callback only for coin tiles.

collisionCallback()

https://newdocs.phaser.io/docs/3.55.2/Phaser.Tilemaps.Tile#collisionCallback

Sorry, my mistake, it should be

// PB TILEMAP
coinLayer.setTileIndexCallback(61, hitCoin);
this.physics.add.overlap(this.player, coinLayer);

I’ve only found example of use in Phaser 2 :confused:

It still doesn’t work. Function Hitcoin is not triggered and I don’t know why.
I’ve done exactly what you said, I don’t understand why it doesn’t work.

var config = {
    type: Phaser.AUTO,
    width: 1200,
    height: 700,
    scene: {
        preload: preload,
        create: create,
        update: update
    },
    physics : {
        default : "arcade",
        arcade : {
            debug: true,
            gravity: { y: 1000 },
        }
    }
};

var game = new Phaser.Game(config);
var coinLayer;
var coinsCollected = 0;
var cooldown = 0;


function preload (){
    this.load.tilemapTiledJSON('map',"../JSON/big_head/mapDef.json");

    this.load.image("tiles","../img/big_head/morning.png");
    //this.load.image("coin","../img/big_head/coin.png");
    this.load.atlas('player', '../img/big_head/player.png', '../JSON/big_head/player.json');

    //this.load.image('spike', '../img/big_head/spike.png');
    this.load.spritesheet('coin', '../img/big_head/coin.png', { frameWidth: 32, frameHeight: 32 });

}

function create (){
    
    this.cursors = this.input.keyboard.createCursorKeys();

    /********************************/
    /*                              */
    /* --  Création de la carte --  */
    /*                              */
    /********************************/
    
    const map = this.make.tilemap({ key: "map", tileWidth: 1400, tileHeight: 40});
    const tileset = map.addTilesetImage("morning_adventures_tileset_16x16","tiles");


    /************************************/
    /*                                  */
    /* --  Création des plateformes --  */
    /*                                  */
    /************************************/

    const platforms = map.createLayer('back', tileset, 0, 0);
    //platforms.setCollisionByExclusion(-1, true);

    /*************************************/
    /*                                   */
    /* --  Création des récupérables --  */
    /*                                   */
    /*************************************/

    var coinTiles = map.addTilesetImage('coin');
    coinLayer = map.createLayer('items', coinTiles, 0, 0);


    platforms.setCollisionBetween(1, 60);

    /********************************/
    /*                              */
    /*  --  Création du perso   --  */
    /*                              */
    /********************************/ 

    this.player = this.physics.add.sprite(0, 0, 'player').setCollideWorldBounds(true);
    this.player.setScale(0.35);
    this.physics.add.collider(this.player, platforms);

    coinLayer.setTileIndexCallback(61, hitCoin);
    this.physics.add.overlap(this.player, coinLayer);

    /********************************/
    /*                              */
    /* --  Gestion de la caméra --  */
    /*                              */
    /********************************/

    this.cameras.main.setBounds(0, 0, 15400, 480);
    this.physics.world.setBounds(0, 0, 15400, 480);

    this.cameras.main.setZoom(1.6);

    this.cameras.main.startFollow(this.player, true, 0.08, 0.08);

    /********************************/
    /*                              */
    /*   --  Création du texte  --  */
    /*                              */
    /********************************/


    text = this.add.text(1, 1, '', {
        fontSize: '20px',
        fill: '#ffffff'
    });
    text.setScrollFactor(0);
    updateText();
   
    /********************************/
    /*                              */
    /*   --  Player animations  --  */
    /*                              */
    /********************************/


    this.anims.create({
        key: 'walk',
        frames: this.anims.generateFrameNames('player', { prefix: 'p1_walk', start: 1, end: 11, zeroPad: 2}),
        frameRate: 10,
    });
}

function update (time, delta)
{
    this.player.setVelocityX(0);

    if (this.cursors.left.isDown)
    {
        this.player.setVelocityX(-200);
        this.player.flipX = true;
        this.player.anims.play('walk', true);

    }
    else if (this.cursors.right.isDown)
    {
        this.player.setVelocityX(200);
        this.player.flipX = false;
        this.player.anims.play('walk', true);
    }

    if ((this.cursors.up.isDown || this.cursors.space.isDown) && this.player.body.onFloor() || (this.player.body.onWall() && (this.cursors.up.isDown || this.cursors.space.isDown)))
    {    
        if(cooldown == 0 || time - cooldown >= 600){
            this.player.setVelocityY(-340);
                cooldown = time;
        }
    }

    if (this.cursors.left.isDown && this.player.x > 0)
    {
        //this.player.setAngle(-90);
        this.player.x -= 2.5;
    }
    else if (this.cursors.right.isDown && this.player.x < 3392)
    {
        //this.player.setAngle(90);
        this.player.x += 2.5;
    }
}

function hitCoin (sprite, tile)
{
    coinLayer.removeTileAt(tile.x, tile.y);
    coinsCollected += 1;

    updateText();

    console.log("coucou")

    return true;
}

function updateText ()
{
    text.setText(
        '\nCoins collected: ' + coinsCollected
    );
}


Thanks a lot for your help

Are you sure index 61 is correct?

Yes I checked.
Here is my tiledmap code (the beginning) :

 <tileset firstgid="61" name="coin" tilewidth="16" tileheight="16" tilecount="16" columns="4">
  <image source="../Téléchargements/2/coin.png" width="64" height="64"/>
 </tileset>

Isn’t it “first gid” ?