You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

matter.js中拆分的多凸多边形组合体被挤压变形如何解决?

解决matter.js凹多边形拆分后被挤压到中心的问题

核心问题分析

你遇到的挤压问题,本质是顶点坐标的参照系错误:Bodies.fromVertices要求传入的顶点是相对于刚体位置(前两个x、y参数)的局部坐标,但你用的是全局屏幕坐标,导致刚体质心计算偏移,再加上约束的拉扯,最终所有凸多边形被挤到错误的中心。

解决方案步骤

1. 转换顶点坐标为局部坐标

先计算所有顶点的全局中心,以此作为刚体的全局位置,再将每个顶点减去这个中心坐标,得到局部坐标:

import m from "matter-js";

// 替换为你的凸多边形顶点数组(每个子数组对应一个凸多边形的全局坐标点)
const globalVertices = [
  [[100, 50], [150, 50], [150, 100]],
  [[150, 100], [200, 50], [150, 50]],
  // ... 其他凸多边形的点
];

// 计算所有点的全局中心(刚体的目标位置)
let totalX = 0, totalY = 0, pointCount = 0;
globalVertices.forEach(polygon => {
  polygon.forEach(([x, y]) => {
    totalX += x;
    totalY += y;
    pointCount++;
  });
});
const bodyPos = { x: totalX / pointCount, y: totalY / pointCount };

// 转换为局部坐标(相对于刚体中心)
const localVertices = globalVertices.map(polygon => 
  polygon.map(([x, y]) => ({ x: x - bodyPos.x, y: y - bodyPos.y }))
);

2. 正确创建复合刚体与约束

使用转换后的局部顶点创建刚体,并配置约束(如果需要):

const engine = m.Engine.create();
const render = m.Render.create({
  engine,
  canvas,
  options: { width: 800, height: 600, wireframes: false }
});

// 创建复合刚体
const ramp = m.Bodies.fromVertices(bodyPos.x, bodyPos.y, localVertices, {
  stiffness: 0.7,
  render: { fillStyle: '#888' }
});

// 约束配置(固定刚体位置时使用)
const rampConstraint = m.Constraint.create({
  bodyA: ramp,
  pointB: bodyPos,
  length: 0,
  stiffness: 0.7
});

m.Composite.add(engine.world, [ramp, rampConstraint]);

// 正确的动画循环(避免setInterval嵌套requestAnimationFrame)
function update() {
  m.Engine.update(engine);
  requestAnimationFrame(update);
}
update();

m.Render.run(render);

3. 手动组合多个刚体的替代方案

如果手动创建每个凸多边形刚体,需给它们设置同一个碰撞组,避免互相碰撞:

const composite = m.Composite.create();
const collisionGroup = m.Body.nextGroup(true); // 共用碰撞组

globalVertices.forEach(polygon => {
  // 以多边形第一个点为初始位置,创建凸多边形刚体
  const [firstX, firstY] = polygon[0];
  const body = m.Bodies.polygon(firstX, firstY, polygon.length, 10, {
    collisionFilter: { group: collisionGroup },
    stiffness: 0.7
  });
  m.Composite.add(composite, body);
});

m.Composite.add(engine.world, composite);

关键注意事项

  • 绝对不要混用全局坐标和局部坐标:fromVertices的顶点必须是相对于刚体位置的局部值。
  • 动画循环直接用requestAnimationFrame驱动,不要嵌套setInterval,避免帧同步问题。
  • 若不需要刚体移动,直接设置isStatic: true即可,无需额外约束。

内容的提问来源于stack exchange,提问作者Patrick Martin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 06:27:52