javascriptsvgphaser-frameworkmatter.js

Create physics body from svg in phaser with matter.js


I'm loading a svg as xml in the preload function:

this.load.xml("xml-pipe-bottom", "assets/svg/shape_pipe_b.svg");

and create a body and the svg as sprite:

const shapeBody = this.matter.add.fromSVG(
  0,
  0,
  this.cache.xml.get(xmlKey)
)
shapeBody.ignoreGravity = true;

const shape = this.matter.add.sprite(400, 400, svgKey)
  .setIgnoreGravity(true)
  .setExistingBody(shapeBody)

matter debug is enabled and it looks like this:

enter image description here

the svg is just a brick, nothing complicated. i tried other shapes as well, but the generated body is always the same.

pathseq.js is loaded.

are there any additional steps required?

edit:

SVG:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
  width="50mm"
  height="50mm"
  viewBox="0 0 50 50"
  version="1.1"
  id="svg1"
  xmlns="http://www.w3.org/2000/svg"
>
  <defs
    id="defs1"/>
  <g
    id="g2"
    style="display:none">
    <path
      id="rect1"
      style="fill:#000000;stroke-width:0.264583"
      d="M 50.000049,0 A 50,50 0 0 1 0,50.000049 h 50.000049 z"/>
    <path
      id="rect2"
      style="fill:#000000;stroke-width:0.264583"
      d="M 0,0 V 30.000236 A 30,30 0 0 0 30.000236,0 Z"/>
  </g>
  <g
    id="g2-8"
    transform="matrix(-1,0,0,1,40.739534,-5.55625)"
    style="display:none">
    <path
      id="rect1-8"
      style="fill:#000000;stroke-width:0.264583"
      d="M 40.739583,5.556201 A 50,50 0 0 1 -9.2604657,55.55625 H 40.739583 Z"/>
    <path
      id="rect2-2"
      style="display:inline;fill:#000000;stroke-width:0.264583"
      d="M -9.2604167,5.55625 V 35.556486 A 30,30 0 0 0 20.739819,5.55625 Z"/>
  </g>
  <g
    id="g2-8-1"
    transform="matrix(-1,0,0,1,40.739534,44.443799)"
    style="display:none">
    <path
      id="rect1-8-7"
      style="fill:#000000;stroke-width:0.264583"
      d="M 40.739583,5.556201 A 50,50 0 0 1 -9.2604657,55.55625 H 40.739583 Z"/>
    <path
      id="rect2-2-1"
      style="display:inline;fill:#000000;stroke-width:0.264583"
      d="M -9.2604167,5.55625 V 35.556486 A 30,30 0 0 0 20.739819,5.55625 Z"/>
  </g>
  <rect
    style="display:none;fill:#000000;stroke-width:0.264583"
    id="rect3"
    width="30.000284"
    height="50.00005"
    x="19.999716"
    y="0"/>
  <rect
    style="display:none;fill:#000000;stroke-width:0.264583"
    id="rect3-7"
    width="30.000284"
    height="50.00005"
    x="-3.5527137e-15"
    y="0"/>
  <rect
    style="display:none;fill:#000000;stroke-width:0.264583"
    id="rect3-7-2"
    width="30.000284"
    height="50.00005"
    x="19.999716"
    y="-50"
    transform="rotate(90)"/>
  <rect
    style="display:inline;fill:#000000;stroke-width:0.264583"
    id="rect3-7-2-1"
    width="30.000284"
    height="50.00005"
    x="0"
    y="-50"
    transform="rotate(90)"/>
</svg>


Solution

  • It turned out that you have to pass the "path"-element not the "svg"-element:

    const svgXmlShape = this.cache.xml.get(xmlKey) as XMLDocument;
    [...svgXmlShape.documentElement.querySelectorAll("svg path")]
          .map((svgPath) => {
            const vertices = this.Svg.pathToVertices(svgPath, 1)...
    

    you can reduce the svg to:

    <svg
       width="100mm"
       height="100mm"
       viewBox="0 0 100 100"
       version="1.1"
       id="svg1"
       xmlns="http://www.w3.org/2000/svg">
      <path
         style="fill:#000000;stroke-width:0.264583"
         d="M 0,0 V 100 H 100 L 50,50 H 32.85849 Z"
         id="path5" />
    </svg>