I want to create a chain from a path that consists of equidistant points in the plane. My idea is to create the chain with
const group = Matter.Body.nextGroup(true);
const composite = Matter.Composites.stack(
endpoints[0].x,
endpoints[0].y,
endpoints.length,
1,
10,
10,
(x: number, y: number) =>
Matter.Bodies.rectangle(x, y, size, thickness, {
collisionFilter: { group },
})
);
Matter.Composites.chain(composite, 0.5, 0, -0.5, 0, {
stiffness: 0.5,
length: 2,
});
and then move the positions of the bodies with
composite.bodies.forEach((body, index) => {
if (index === endpoints.length - 1) return;
const start = endpoints[index];
const end = endpoints[index + 1];
const angle = Math.atan2(end.y - start.y, end.x - start.x) % (Math.PI * 2);
const mid = { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 };
Matter.Body.setAngle(body, angle);
Matter.Body.setPosition(body, mid);
});
but it only half works. If the path is drawn horizontally from left to right it seems to work, but if it is drawn in any other direction, like from right to left, the tip of the chain ends up spinning uncontrollably.
Here’s the class with the relevant parts.
class Chain {
composite: Matter.Composite;
constructor(path: Point[], size: number, thickness: number) {
const endpoints = make_path(path, size);
if (!endpoints.length) throw new Error("endpoints.length = 0!");
const group = Matter.Body.nextGroup(true);
const composite = Matter.Composites.stack(
endpoints[0].x,
endpoints[0].y,
endpoints.length,
1,
10,
10,
(x: number, y: number) =>
Matter.Bodies.rectangle(x, y, size, thickness, {
collisionFilter: { group },
})
);
const pin = Matter.Constraint.create({
bodyB: composite.bodies[0],
pointB: { x: 0, y: 0 },
pointA: { x: endpoints[0].x, y: endpoints[0].y },
stiffness: 0.5,
});
Matter.Composites.chain(composite, 0.5, 0, -0.5, 0, {
stiffness: 0.5,
length: 2,
});
Matter.Composite.add(composite, pin);
composite.bodies.forEach((body, index) => {
if (index === endpoints.length - 1) return;
const start = endpoints[index];
const end = endpoints[index + 1];
const angle = Math.atan2(end.y - start.y, end.x - start.x);
const mid = Matter.Vector.create(
(start.x + end.x) / 2,
(start.y + end.y) / 2
);
Matter.Body.setAngle(body, angle);
Matter.Body.setPosition(body, mid);
});
this.composite = composite;
}
}
The bug still happens if I only change the position, and leave the initial angle alone.
For completeness, here’s how the path is created https://jsfiddle.net/0ro7duLa/.