matter-js
matter-js copied to clipboard
Angle constraints
Distance constraints are really nice, how about angle constraints?
That would make it possible to remove those two "diagonal constraints" from this example: http://jsbin.com/risahi/4/edit
This is definitely on my list, I'll keep this thread updated, thanks!
+1
+1
+1
+1
What are/were your thoughts on the best way to implement this @liabru? I really need this and would be willing to help.
+1
+1111111111
+1
+1
@liabru Is there any progress on this one? I need this for my project so much that I'm looking into hacking it in myself. But, I'm concerned I might not figure out how to do it in a way that conserves momentum, etc.
FWIW, here's how I implemented angular constraints for another verlet lib: https://github.com/softfab/tshirt/blob/master/src/verlet-constraint-angle-2d.js
I will bury a timecapsule with instructions for my great grandchildren on how to complete my project when angle constraints are finally added to this library in 2050
Anyone wanna help @liabru out? It's an open source library, not a paid service ;)
+1
I've come up with a solution for this that seems like a good workaround until this is implemented. For my project I wanted to limit the extended and contracted angle between the upper arm and lower arm of a character to mimic normal elbow behavior. You can check it out below in action...
How it works
- Create a constraint between the two bodies that are linked with a revolute constraint
- Ie.. a 0 distance .7 stiffness regular constraint
- Set the constraint stiffness to 0
- The length doesn't matter yet
- It seems like it works well if you offset the constraint from the bodies as seen in the gif
- Every frame, measure the distance between the two attachment points of the constraint
- Set some some minimum and & maximum rules around this distance
- For my case, I am checking to see if the the distance is greater than 120
- If it's greater than 120,
- I set the stiffness of the constraint to 1
- I set the length of the constraint to 120
- For my case, this does enough to limit the angle for both an extended and contracted arm but you could layer a bunch of these together to get the constraints you want.
In general, I think this might be a good approach and can be adapted for other scenarios.
Some Code
This is the constraint setup
let testConstraint = Constraint.create({
bodyA: upperArm,
pointA: { x: 120, y: 0 },
bodyB: lowerArm,
pointB: { x: 120, y: 0 },
stiffness : 0,
length: 100
});
This gets the distance between the attachment points
let uX = 120; // This is the x offset of the constraint for the upper arm
let uY = 0; // This is the y offset of the constraint for the upper arm
let uA = upperArm.angle;
let upperX = upperArm.position.x + uX * Math.cos(uA) - uY * Math.sin(uA);
let upperY = upperArm.position.y + uX * Math.sin(uA) + uY * Math.cos(uA);
let lX = 120; // This is the x offset of the constraint for the lower arm
let lY = 0; // This is the x offset of the constraint for the lower arm
let lA = lowerArm.angle;
let lowerX = lowerArm.position.x + lX * Math.cos(lA) - lY * Math.sin(lA);
let lowerY = lowerArm.position.y + lX * Math.sin(lA) + lY * Math.cos(lA);
var xDelta = upperX - lowerX;
var yDelta = upperY - lowerY;
var distance = Math.sqrt( xDelta * xDelta + yDelta * yDelta );
if (distance > 120){
testConstraint.length = 120;
testConstraint.stiffness = 1;
} else {
testConstraint.stiffness = 0;
}
cc @AndrewBrownK @Twosies @joel-simon @davearel in case this still matter to you haha.
My use case was to implement a servo arm. What I ended up doing was to add two revolute constraints; one for the pivot point (like flukeout) and one farther out (unlike in flukeout's example, this is also a revolute constraint!). The constraint can be modified at runtime to change to which angle the dependent element should go.
const anchor = Matter.Bodies.rectangle(200, 350, 50, 50, {
density: 1,
frictionAir: 0.4,
});
const arm = Matter.Bodies.rectangle(200, 200, 10, 200, {
// in this example I don't want the anchor to rotate too much when the arm moves
density: 0.01,
frictionAir: 0.1,
});
// this constraint remains constant
const pivot = Matter.Constraint.create({
bodyA: anchor,
pointA: { x: 0, y: -50 },
bodyB: arm,
pointB: { x: 0, y: 100 },
});
const control = Matter.Constraint.create({
bodyA: anchor,
// the pointA is modified to change the point to which the arm should be fixed
pointA: { x: 0, y: -100 },
bodyB: arm,
pointB: { x: 0, y: 50 },
});
Matter.World.add(this.simulation.world, [anchor, arm, pivot, control]);
setTimeout(() => {
// change the control point later
// should use sine and cosine, this is fine for the demo
control.pointA = { x: 20, y: -100 };
}, 1000);
I think by making the pivot
constraint stiffer than the control
constraint, you can ensure that the rotation point is at/closer to the pivot, and by adjusting the distance between pivot and control, you can control the "angular stiffness".
I've opened PR #837 which adds angle constraints, those interested please take a look, try them out and let me know if you spot any issues or just if they work nicely for your use case.
Thanks for holding on here everyone!
(@AndrewBrownK get ready to dig up that time capsule)
Phew! I really needed this feature. Was quite exciting reading through the comments starting 6 years ago and finding that it had finally happened by 2020. Good job @liabru !
Yes! I need to come back to this though, it's not merged as there were a few cases that were not stable (chains). I could probably release it with some caveats I suppose.
@liabru any updates on this? Thanks!
So what about angularStiffness or something like this? 8 years passed since this topic has started 😀
I'm trying to simulate some piston-like things and this angle constraint would make things significantly easier.