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
相关产品推荐
相关产品推荐

