'How to get target who are touching on a specific sprite

I am trying to make a mini-game by phaser.js. In my idea. A sprite object can collided to a static sprite and continually perform desired effect if they are stick together. However, when I handle them with this.physics.add.collider, the callback function just run once.

Search for API document. I find the touching event can be judged by object.body.touching. But seen it can only return the facing. So I wonder how to get the object who are touching on the specific direction of a sprite? Or the function is need to handle by handy?

Thanks for your help.



Solution 1:[1]

If you more "detailed"/"better" physics functions in phaser, you could use matter physics engine.
(It is as easy as arcade to setup)

With matter there are better options, like the "collisions events", using matter you could use the event collisionactive. (link to the documentation)

collisionactive executes as long as the colliding objects touch.

Like this you know the exact object(s) touching. (And if you need the direction you could find it with the x and y postions of the objects, or the velocity of the impact)

Here a demo from the offical website, showing collisionstart Event https://phaser.io/examples/v3/view/physics/matterjs/collision-event

Here a small with matter demo:

// Minor formating for stackoverflow
document.body.style = "display: flex;flex-direction: column;";  

var config = {
    type: Phaser.AUTO,
    width: 536,
    height: 153,
    backgroundColor: '#1b1464',
    physics: {
        default: 'matter',
        matter: {
          debug:true,
          gravity:{y:0, x:0}
        }
    },
    scene: {
        create: create
    }
};

var game = new Phaser.Game(config);

var counter = 0;
var gOverlay;
function create ()
{
    var blockA = this.matter.add.image(50, 80, 'block1');

    var blockB = this.matter.add.image(300, 80, 'block1').setStatic(true);
    var text = this.add.text(10,10, 'Not touching')
    blockA.setVelocityX(3);
    
    
    gOverlay = this.add.graphics();

    this.matter.world.on('collisionstart', function (event, bodyA, bodyB) {
        text.setText(text.text + '\nHIT')
        drawDirectionArrow(bodyA, bodyB)
    });

    this.matter.world.on('collisionactive', function (event, bodyA, bodyB) {
        text.setText(`Touching: ${counter++}`)
        if(counter > 60 ) {
            counter = 0;
            blockA.setVelocityX(-2);
        }
    });

    this.matter.world.on('collisionend', (function (event, bodyA, bodyB) {
        text.setText(text.text + '\nNot touching');
        gOverlay.clear();
        this.time.delayedCall(2000, _ => blockA.setVelocityX(5)); 
    }).bind(this));
}

function drawDirectionArrow(a, b){
  gOverlay.clear();
  
  gOverlay.fillStyle( 0xFF00FF);
  gOverlay.fillTriangle(a.position.x, a.position.y, b.position.x, b.position.y - 10, b.position.x, b.position.y + 10);
  
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js">
</script>

Update:
If you need/want to use arcade physics, here is a similar demo, with a small workaround using a second physics-object to check for overlap.

Arcade - Physics workaround - Demo:

// Minor formating for stackoverflow
document.body.style = "display: flex;flex-direction: column;";  

var config = {
    type: Phaser.AUTO,
    width: 536,
    height: 153,
    backgroundColor: '#1b1464',
    physics: {
        default: 'arcade',
        arcade: {
          debug:true,
        }
    },
    scene: {
        create: create
    }
};

var game = new Phaser.Game(config);

var counter = 0;
var gOverlay;

function create () {
    var blockA = this.physics.add.image(50, 80, 'block1').setOrigin(.5);
    var blockB = this.physics.add.image(300, 80, 'block1').setOrigin(.5);
    
    // Helper
    var blockBx = this.add.rectangle(300, 80, 34, 34);
    
    this.physics.add.existing(blockBx);
    
    blockB.setImmovable();
    
    var text = this.add.text(10,10, 'Not touching')
    blockA.setVelocityX(50);
    
    gOverlay = this.add.graphics();
    
    this.physics.add.collider(blockA, blockB,  function ( bodyA, bodyB) {
        drawDirectionArrow(bodyA, bodyB);
    })
    
    this.physics.add.overlap(blockA, blockBx, function ( bodyA, bodyB) {
        text.setText(`Touching: ${counter++}`);
        if(counter > 60 ) {
            counter = 0;
            gOverlay.clear();
            blockA.setVelocityX(-50);
            text.setText('Not touching');
            this.time.delayedCall(2000, _ => blockA.setVelocityX(50)); 
        }
    }, null, this);
}

function drawDirectionArrow(a, b){
  gOverlay.clear();
  
  gOverlay.fillStyle( 0xFF00FF);
  gOverlay.fillTriangle(a.x, a.y, b.x, b.y - 10, b.x, b.y + 10);
  
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js">
</script>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1