Search code examples
javascriptgame-enginephaser-framework

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

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

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

    collisionactive executes as long as the two 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>