Stop physics joints from separating

In the manual it says:
"A rope joint is one which is used to join two instances that you want to keep a constant distance apart, no matter what other forces are acting on it. With a distance joint, you can get "joint stretching" where the two fixtures will separate and behave strangely should too much stress be put on the joint, however the rope joint does not do this and will not stretch any further than the maximum defined length."

And yet:


The code if you need it.
Basically just create a new chain instance, and then join it to the previous with a rope join.

GML:
if mouse_check_button_pressed(mb_left)
    {
    // Position of old chain
    var oldChainX      = chainInst.x;
    var oldChainY      = chainInst.y;
 
    // Edge of old chain
    var oldChainEndX   = oldChainX    + lengthdir_x(32,-chainInst.phy_rotation);
    var oldChainEndY   = oldChainY    + lengthdir_y(32,-chainInst.phy_rotation);
 
    // Start pos of new chain (+ gap in between)
    var newChainStartX = oldChainEndX + lengthdir_x(1,-chainInst.phy_rotation);
    var newChainStartY = oldChainEndY + lengthdir_y(1,-chainInst.phy_rotation);
 
    // Middle pos of new chain
    var newChainX      = newChainStartX + lengthdir_x(32,-chainInst.phy_rotation);
    var newChainY      = newChainStartY + lengthdir_y(32,-chainInst.phy_rotation);
 
    // Spawn next chain at middle
    var newChainInst   = instance_create_depth(newChainX,newChainY,0,obj_Chain);
 
    // Join together
    physics_joint_rope_create(newChainInst,chainInst,oldChainEndX,oldChainEndY,newChainStartX,newChainStartY,2,false);
 
    chainInst = newChainInst;
    }
 

Attachments

Last edited:
I'm getting much cleaner results using a revolute join:



but I can still do this if the chain gathers enough momentum and swings around:
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
I'm pretty sure all you need to do is substitute the distance joint for a rope joint. IIRC, they are immune to this "stretching" that you are seeing.
 

Bart

WiseBart
Not entirely sure why this is happening with the rope joint, though there might be some indication.
The physics engine does a number of iterations behind the scenes, so results are never "exact". What you get out of it is always an approximation.
And depending on how you configure it, the results can be more precise or less precise.
I forgot where I read it, but just like everything else, the joints are "simulated" by performing these iterations.
They aren't actually held firmly in place, rather they're kept in place by applying forces/impulses/torques. Which, once again, results in an approximation.
One page that gives some explanation is this one: Box2D: Loose Ends. What you're seeing here could be related to points 4 and 6 and perhaps also to point 2.

So probably the best (and perhaps only?) way to get an improvement is by increasing the number of iterations (physics_world_update_iterations) and/or the update speed (physics_world_update_speed). Not sure what those do exactly but in short, higher values mean a better result, a better approximation.

(Perhaps as an alternative or combined with the above it could help to tell the engine that those instances should be treated as fast moving by setting phy_bullet to true?)
 
Last edited:
So probably the best (and perhaps only?) way to get an improvement is by increasing the number of iterations (physics_world_update_iterations) and/or the update speed (physics_world_update_speed). Not sure what those do exactly but in short, higher values mean a better result, a better approximation.
Setting the iterations to 30 (maximum recommended by manual) and update speed to room_speed*2 (on suggestion of manual) provides essentially no better effect when using the rope join.

One page that gives some explanation is this one: Box2D: Loose Ends. What you're seeing here could be related to points 4 and 6 and perhaps also to point 2.
This is very insightful though, thanks for sharing this!

I think my problem is most likely this one:
2. Chains of bodies connected by joints may stretch if a lighter body is supporting a heavier body. For example, a wrecking ball connect to a chain of light weight bodies may not be stable. Stability degrades as the mass ratio passes 10:1.

My player object is using ridiculous forces in order to move responsively, so I think my only solution here is to use revolute joins, and not use any join between the player and tail. Instead I should use forces, that way I can control how powerful the pulling is on the end chain, and I can limit it.
 

Roldy

Member
Is this just a problem people have accepted and there's no solution?
Yes and no. These limitations exist in pretty much all realtime physics simulations. However, in additon to what @Bart suggested. I would suggest adjusting your geometry until something works. Try things like:

  • make each rigid body in your chain smaller and more of them.
    • Especially don't make them the size they can get caught in the hallways.
    • The size you have now they can't even rotate within the hall, meaning the solver is more constricted
  • Make the rigid bodies in the chain and/or the static geometry rounded and smooth
    • More easily to slip passed obstacles and join up.
    • Capsules instead of rectangles.
    • Low friction etc..
  • Limit the speed that you are moving these bodies relative to the thickness of the geometry (increases iterations is the alternative to this).
  • Consider a method for 'telling' the simulation where you want to move.
    • It is very possible you have this set up as a uniform chain
    • So when simulating the middle chains, it really doesn't know you want everything to follow the man.
    • If the tail gets stuck everything might solve to stick with the tail instead of following the man
      • because to the solver either direction is a solution.
      • So find a way to weight it that following the man is the preferred/weighted solution

I have only messed with Box2D occasionally, and very limited within GMS2, but the above suggestions would be general suggestions I would give for any physics simulation. There will probably be more Box2D specific tweaks people can suggest to you.
 
Last edited:
Thank you, those look like some interesting suggestions I'll try them now.

Currently this is what I'm trying with questionable success?
 
D

Deleted member 16767

Guest
I think you forgot one ball at the bottom corner.
 
I think you forgot one ball at the bottom corner.
There are quite a lot missing, but I didn't wanna spend time placing them all in case it didn't work.

So I upped the physics world iterations to 30 and physics speed to 2x room speed:


It's not the worst result? You have to make sure the wheels stick out a lot or the chain still gets caught on the corner when it pops through.

Adjusting phy_joint_damping_ratio and phy_joint_frequency on your distance joints will be most effective in reducing the joints separating.
Adjusting the pixels to metres ratio may also help.
Good to see people using the physics :)
Are you a developer for box 2D? šŸ˜®
 

Vusur

Member
Huh, was fun observing this.
Your first post looked more like a puzzle concept. "Don't break the chain!". Only a "Game Over" was missing. :)
The last post looked like something useful for other cases like having a chainball attached to the character for story reasons.

Thanks for sharing this journey!
 
Your first post looked more like a puzzle concept. "Don't break the chain!". Only a "Game Over" was missing. :)
The last post looked like something useful for other cases like having a chainball attached to the character for story reasons.
Wow nice ideas, they're all yours if you want! I love the don't break the chain one.

Adjusting phy_joint_damping_ratio and phy_joint_frequency on your distance joints will be most effective in reducing the joints separating.
Adjusting the pixels to metres ratio may also help.
So I'm not having much luck with these. I switched back to distance joints to test this, but whatever values I use it always seems to look like this:
Do you have any recommended values?

It is very possible you have this set up as a uniform chain
might solve to stick with the tail instead of following the man because to the solver either direction is a solution. So find a way to weight it that following the man is the preferred/weighted solution
I like the way you're thinking, but aside from generating the chain in the opposite direction, what can be done to solve this?

--------------------
So I've made the wheels stop bobbing so much, and widened the collision box for the chains.

At 100 chain instances, 30 iterations + 60 physics speed, it's running at 800fps real so not too bad.


I've uploaded the project file for anyone that wants to have a look.
In summary, the set up is:

Player:
Collides with: The wall
I don't want the player to be able to hit the support wheels, they're only for the chains.

Chain link:
Collides with: Walls and wheels
I set the density of the chain links to 0.01 and the density of the wheels to 0.999 so they would have incredibly minimal impact.
The controller's creation code used to create all the chains is here:
GML:
var chainWidth = 10;
playerInst = instance_create_depth(0,0,0,obj_Player);
var chainInst = noone;
physics_world_update_iterations(30);
physics_world_update_speed(room_speed*2);
repeat 100
    {
    if instance_exists(chainInst)
        {
        // Position of old chain
        var oldChainX      = chainInst.x;
        var oldChainY      = chainInst.y;
   
        // Edge of old chain
        var oldChainEndX   = oldChainX    + lengthdir_x(chainWidth,-chainInst.phy_rotation);
        var oldChainEndY   = oldChainY    + lengthdir_y(chainWidth,-chainInst.phy_rotation);
        }
    else
        {
        chainInst = playerInst;
        oldChainEndX = chainInst.x;
        oldChainEndY = chainInst.y;
        }
   
    // Start pos of new chain (+ gap in between)
    var newChainStartX = oldChainEndX + lengthdir_x(1,-chainInst.phy_rotation);
    var newChainStartY = oldChainEndY + lengthdir_y(1,-chainInst.phy_rotation);
   
    // Middle pos of new chain
    var newChainX      = newChainStartX + lengthdir_x(chainWidth,-chainInst.phy_rotation);
    var newChainY      = newChainStartY + lengthdir_y(chainWidth,-chainInst.phy_rotation);
   
    // Spawn next chain at middle
    var newChainInst   = instance_create_depth(newChainX,newChainY,0,obj_Chain);

   
    // Join together
    //physics_joint_rope_create(newChainInst,chainInst,oldChainEndX,oldChainEndY,newChainStartX,newChainStartY,2,false);
    physics_joint_revolute_create(newChainInst,chainInst,oldChainEndX,oldChainEndY,0,0,false,0,0,false,false);
    //var join = physics_joint_distance_create(newChainInst,chainInst,oldChainEndX,oldChainEndY,newChainStartX,newChainStartY,false);
    //physics_joint_set_value(join,phy_joint_damping_ratio,0.5);
    //physics_joint_set_value(join,phy_joint_frequency,15);
   
    chainInst = newChainInst;
    }
I used revolute joins as they seem to be the strongest at reliably keeping the chain stuck together.

Wheels:
Collides with: Nothing.
On creation, makes note of x,y and uses:
GML:
var amount = 100;
phy_linear_damping = 20;
physics_apply_force(x,y,(goToX-x)*amount,(goToY-y)*amount);
to stay put despite the chains trying to move them.
However, their angular damping is 0 so they spin freely, and their friction is set to 1 so they hook onto the chains and spin at any opportunity.

Walls:
Collides with: Nothing.
Density set to 0 so they don't move

I ended up leaving the room pixels to meters as 0.1
Collision groups for all of them are set at 0.
 
Last edited:

Mert

Member
Increasing the iteration steps and the speed fixed my issue actually. But for more detailed cases, I think there'll be a lot to do
 
I had a look at your project and twerked a few things I think I got it working pretty good https://www.dropbox.com/s/r2wlsvo9fi18w7t/whips and chains n stuff.yymps?dl=0
I hope this helps
Wow, nice! That's a huge improvement for distance joints!

But if you look at the chain immediately behind the player, the chain links are vibrating quite hard.



But they don't seem to do that using revolute joins:

Other than adding
GML:
physics_joint_set_value(join,phy_joint_damping_ratio,10);
physics_joint_set_value(join,phy_joint_frequency,60);
did you change anything else? The chains look like they're connected closer together?
 
Last edited:
did you change anything else? The chains look like they're connected closer together?
I changed a few different things. Pixel to metre ratio, joint distance, physics iterations and speed, object friction /density etc.
With physics I think it's important to look at all the variables.
Everyone is different and programming is expressive and there are many ways to achieve similar results.
It looks like you have got success with revolute joints and that is the best outcome, because you figured it out yourself. Patience is key here.
 
Top