Phaser3, Matter physics, Calculate distance between a point and a physics shape

Viewed 70

I'm currently working on a Phaser 3 game project, using Matter Physics. I created a matter.image object. In order to create a physics shapes, which I have to determine the coordinates of each vertex of the polygon outline like this, I used Physics Editor (https://www.codeandweb.com/physicseditor). It generates a JSON file include vertices, you can refer to Attachment #1.

Now I want to calculate the horizontal distance between the physics shape and a point. For example, in this figure, the blue one in the left is physics shape, and the blue one in the left is the point, and the green line is the horizontal distance I want to calculate.

Code used to create the object:

// in the preload() function
this.load.json('sprite', '../assets/chisato-sprite.json');

// in the create() function
sprites = this.cache.json.get('sprite');
chisatoLeft = this.matter.add.image(480, 425, 'chisatoLeft', null, { shape: sprites.left });

How can I do that?

Thanks in advance.


Attachment #1 Excerpt of the json file

{
    "generator_info": "Shape definitions generated with PhysicsEditor. Visit https://www.codeandweb.com/physicseditor",
    "left": {
        "type": "fromPhysicsEditor",
        "label": "left",
        "isStatic": true,
        "density": 0.10000000149011612,
        "restitution": 0,
        "friction": 0.10000000149011612,
        "frictionAir": 0.009999999776482582,
        "frictionStatic": 0.5,
        "collisionFilter": {
            "group": 0,
            "category": 1,
            "mask": 255
        },
        "fixtures": [
            {
                "label": "",
                "isSensor": false,
                "vertices": [
                    [ { "x":71, "y":226.5 }, { "x":76.5, "y":215 }, { "x":57.5, "y":216 } ],
                    [ { "x":166, "y":197.5 }, { "x":182.5, "y":169 }, { "x":164.5, "y":177 } ],
                    [ { "x":33.5, "y":214 }, { "x":29.5, "y":203 }, { "x":24.5, "y":206 } ],
                    [ { "x":198.5, "y":44 }, { "x":176, "y":38.5 }, { "x":162, "y":48.5 }, { "x":175.5, "y":50 } ],
                    [ { "x":175.5, "y":50 }, { "x":162, "y":48.5 }, { "x":168.5, "y":59 } ],
                    [ { "x":61, "y":223.5 }, { "x":57.5, "y":216 }, { "x":29.5, "y":203 }, { "x":47, "y":215.5 } ],
                    [ { "x":192.5, "y":61 }, { "x":168.5, "y":59 }, { "x":173, "y":68.5 } ],
                    [ { "x":159, "y":195.5 }, { "x":164.5, "y":177 }, { "x":173, "y":68.5 }, { "x":156.5, "y":180 } ],
                    [ { "x":129, "y":17.5 }, { "x":86, "y":10.5 }, { "x":85, "y":10.5 }, { "x":29.5, "y":203 }, { "x":156.5, "y":180 }, { "x":173, "y":68.5 }, { "x":168.5, "y":59 }, { "x":162, "y":48.5 } ],
                    [ { "x":20.5, "y":273 }, { "x":17.5, "y":341 }, { "x":26, "y":399 }, { "x":265.5, "y":381 }, { "x":226, "y":234.5 }, { "x":87.5, "y":231 }, { "x":47, "y":249.5 } ],
                    [ { "x":43, "y":219.5 }, { "x":47, "y":215.5 }, { "x":29.5, "y":203 } ],
                    [ { "x":208.5, "y":166 }, { "x":204.5, "y":130 }, { "x":200, "y":140.5 } ],
                    [ { "x":57.5, "y":216 }, { "x":76.5, "y":215 }, { "x":156.5, "y":180 }, { "x":29.5, "y":203 } ],
                    [ { "x":5.5, "y":152 }, { "x":24.5, "y":206 }, { "x":29.5, "y":203 }, { "x":85, "y":10.5 }, { "x":13.5, "y":64 }, { "x":5.5, "y":92 } ],
                    [ { "x":52.5, "y":20 }, { "x":32, "y":35.5 }, { "x":13.5, "y":64 }, { "x":85, "y":10.5 } ],
                    [ { "x":185.5, "y":201 }, { "x":189, "y":199.5 }, { "x":200.5, "y":161 }, { "x":200, "y":140.5 }, { "x":182.5, "y":169 } ],
                    [ { "x":182.5, "y":169 }, { "x":200, "y":140.5 }, { "x":204.5, "y":130 }, { "x":173, "y":68.5 }, { "x":164.5, "y":177 } ],
                    [ { "x":299, "y":400 }, { "x":265.5, "y":381 }, { "x":26, "y":399 } ],
                    [ { "x":87.5, "y":231 }, { "x":226, "y":234.5 }, { "x":217, "y":226.5 }, { "x":152.5, "y":212 }, { "x":92.5, "y":220 } ],
                    [ { "x":152.5, "y":212 }, { "x":156.5, "y":180 }, { "x":76.5, "y":215 }, { "x":92.5, "y":220 } ]
                ]
            }
        ]
    },
1 Answers

To calculate the distance between two specific points in Phaser, you can use the builtin function Phaser.Math.Distance.Between(x1, y1, x2, y2) (link to the documentation).

So you could iterate calculate the point in the world position ( JsonData-Point minus Image position ) and than calculate the distance.

here a possible code snippet, how this could look like.
(assuming all vertices under of the vertices properties are relevant)

let targetPoint = {x:100, y:200};
let listOfDistances = sprites.left.fixtures[0].vertices.flat.map(vertex => {
    return Phaser.Math.Distance.Between( 
        vertex.x - chisatoLeft.x, 
        vertex.y - chisatoLeft.y,
        targetPoint.x,
        targetPoint.y
    );
});

Update 1: I miss read, if you only need the horizontal distances, you can simply subtract the x-coordinates, something like this:

 ...
 let listOfDistances = sprites.left.fixtures[0].vertices.flat().map(vertex => {
    return Math.abs(
        (vertex.x - chisatoLeft.x) -
        targetPoint.x
    );
});

Since a distance can only be a positive number, you would have to use the Math.abs() - function (link to documentation)

And than just calculate the shortes distance (= horizontal distance), with Math.min (link to documenation)

...
let horizontalDistance = Math.min( ...listOfDistances );
...

Update 2:

If you want to get the intersection, this would be the solution:
(documentation for the funtion GetLineToPoints )

 ...
 let targetPoint = { x: 100, y: 200 };

 let points = sprites.left.fixtures[0].vertices.flat().map(vertex => {
     return new Phaser.Geom.Point(vertex.x - chisatoLeft.x, vertex.y - chisatoLeft.y);
 });
 
 let line = new Phaser.Geom.Line(config.width, targetPoint.y, 0, targetPoint.y);

 let interSectingPoint = Phaser.Geom.Intersects.GetLineToPoints( line, points );

 let horizontalDistance = Math.abs(targetPoint.x - interSectingPoint.x);

Update 3:

Here a Phaser running example.
(btw.: for the line the start and end point order is important/makes a difference)

document.body.style = 'margin:0;';

let data = {"fixtures":[{"vertices":[[{"x":71,"y":226.5},{"x":76.5,"y":215},{"x":57.5,"y":216}],[{"x":166,"y":197.5},{"x":182.5,"y":169},{"x":164.5,"y":177}],[{"x":33.5,"y":214},{"x":29.5,"y":203},{"x":24.5,"y":206}],[{"x":198.5,"y":44},{"x":176,"y":38.5},{"x":162,"y":48.5},{"x":175.5,"y":50}],[{"x":175.5,"y":50},{"x":162,"y":48.5},{"x":168.5,"y":59}],[{"x":61,"y":223.5},{"x":57.5,"y":216},{"x":29.5,"y":203},{"x":47,"y":215.5}],[{"x":192.5,"y":61},{"x":168.5,"y":59},{"x":173,"y":68.5}],[{"x":159,"y":195.5},{"x":164.5,"y":177},{"x":173,"y":68.5},{"x":156.5,"y":180}],[{"x":129,"y":17.5},{"x":86,"y":10.5},{"x":85,"y":10.5},{"x":29.5,"y":203},{"x":156.5,"y":180},{"x":173,"y":68.5},{"x":168.5,"y":59},{"x":162,"y":48.5}],[{"x":20.5,"y":273},{"x":17.5,"y":341},{"x":26,"y":399},{"x":265.5,"y":381},{"x":226,"y":234.5},{"x":87.5,"y":231},{"x":47,"y":249.5}],[{"x":43,"y":219.5},{"x":47,"y":215.5},{"x":29.5,"y":203}],[{"x":208.5,"y":166},{"x":204.5,"y":130},{"x":200,"y":140.5}],[{"x":57.5,"y":216},{"x":76.5,"y":215},{"x":156.5,"y":180},{"x":29.5,"y":203}],[{"x":5.5,"y":152},{"x":24.5,"y":206},{"x":29.5,"y":203},{"x":85,"y":10.5},{"x":13.5,"y":64},{"x":5.5,"y":92}],[{"x":52.5,"y":20},{"x":32,"y":35.5},{"x":13.5,"y":64},{"x":85,"y":10.5}],[{"x":185.5,"y":201},{"x":189,"y":199.5},{"x":200.5,"y":161},{"x":200,"y":140.5},{"x":182.5,"y":169}],[{"x":182.5,"y":169},{"x":200,"y":140.5},{"x":204.5,"y":130},{"x":173,"y":68.5},{"x":164.5,"y":177}],[{"x":299,"y":400},{"x":265.5,"y":381},{"x":26,"y":399}],[{"x":87.5,"y":231},{"x":226,"y":234.5},{"x":217,"y":226.5},{"x":152.5,"y":212},{"x":92.5,"y":220}],[{"x":152.5,"y":212},{"x":156.5,"y":180},{"x":76.5,"y":215},{"x":92.5,"y":220}]]}]};

var config = {
    type: Phaser.AUTO,
    width: 536,
    height: 183,
    physics: {
        default: 'arcade',
        arcade: {            
            gravity:{ y: 100 },
            debug: true
        }
    },
    scene: {
        create
    },
    banner: false
}; 

function create () {


   let targetPoint = { x: 300, y: 80 };
   let chisatoLeft = { x: 10, y: 10 };

   let points = data.fixtures[0].vertices.flat().map(vertex => {
   console.info(vertex)
       return new Phaser.Geom.Point(vertex.x - chisatoLeft.x, vertex.y - chisatoLeft.y);
   });
   
   console.info(points, data)
   
   // draw points -> just for the demo
   
   points.forEach( point =>
      this.add.rectangle(point.x, point.y, 5, 5, 0xff0000)
   );
   
   // draw target point -> just for the demo
   
   this.add.rectangle(targetPoint.x, targetPoint.y, 8, 8, 0xffffff).setDepth(2);
   
   // draw line -> just for the demo
   
   this.add.line(0, 0, config.width, targetPoint.y, 0, targetPoint.y, 0x00ff00).setOrigin(0);

   let line = new Phaser.Geom.Line(config.width, targetPoint.y, 0, targetPoint.y);

   let interSectingPoint = Phaser.Geom.Intersects.GetLineToPoints( line, points );
   
   // draw line to intersection -> just for the demo
   this.add.line(0, 0, targetPoint.x, targetPoint.y + 10, interSectingPoint.x, targetPoint.y + 10, 0xffffff).setOrigin(0);

   let horizontalDistance = Math.abs(targetPoint.x - interSectingPoint.x);
   
   this.add.text(config.width-10, 10, `horizontalDistance : ${horizontalDistance.toFixed(2)}`).setOrigin(1,0)
   console.info(horizontalDistance);

}

new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>

Related