Retracting a 'Rope'

Topics: User Forum
Sep 26, 2012 at 1:35 AM

I have built a grappling hook system that uses a series of DistanceJoint 'links' between circle bodies and a FixedDistanceJoint at the end to anchor it to the world. DistanceJoints are currently limited to 0.5 length to provide a good simulation of the rope physics - much longer and it starts ignoring a lot of corners, objects, etc. I need to be able to retract (and extend, but that's later) this rope, pulling the attached player along with it. I have tried simply changing the Length property without success - the player simply stays put.

I have tried using RopeJoints instead with the same results. Setting Frequency on the DistanceJoint also doesn't work, and it creates some aberrant behavior (the rope takes on a mind of it's own). What would be the best way to handle this? Do I need to use RopeJoint and manually apply an Impulse/Force to the player to get them to react?

Oct 22, 2012 at 1:31 PM
Edited Oct 22, 2012 at 1:36 PM

I've also wanted to solve this ,

So far I've come up with the following :

private float shorteningIntereval = 0.08f;
private float shorteningElapsed = 0f;
private bool ropeShortening = false;

// In my HandleInput method 
 public override void HandleInput(InputHelper input, GameTime gameTime)
{
            float elapsed = (float) gameTime.ElapsedGameTime.TotalSeconds;
            if (ropeShortening)
{
       ShortenRope(elapsed);
       return; // I decided to disable actions while the rope is retracting but that's up to you.
} 
            // .. handle the input from player
            if (input.IsNewKeyPress(Microsoft.Xna.Framework.Input.Keys.T)) //The key for shortening the rope (i.e. T)
            {
                if (ropeObjectJoint != null)
                {
                    ShortenRope(elapsed);
                    ropeShortening = true;
                }  
            }
}

// playerCircle is the Body that i use for moving the player in the physics world
// ropeBodies is List for the rope the player is attached to.
private void ShortenRope(float timeElapsed)
        {
            shorteningElapsed += timeElapsed;
            if (shorteningIntereval < shorteningElapsed)
            {
                shorteningElapsed = 0f;
                if (ropeBodies.Count > 1)
                {
                    World.RemoveBody(ropeBodies[1]);
                    ropeBodies.RemoveAt(1);
                    if (ropeBodies.Count == 1)
                    {
                        Body nextBody = playerCircle;
                        RevoluteJoint joint = new RevoluteJoint(ropeBodies[0], nextBody, new Vector2(0f, -0.5f), new Vector2(0, 0.5f));
                        World.AddJoint(joint);
                    }
                    else
                    {
                        Body nextBody = ropeBodies[1];
                        RevoluteJoint joint = new RevoluteJoint(ropeBodies[0], nextBody, Vector2.Zero, new Vector2(0, 0.5f));
                        World.AddJoint(joint);
                    }
                }
                else
                {
                    World.RemoveBody(ropeBodies[0]);
                    ropeBodies.RemoveAt(0);
                    ropeShortening = false;
                }
            }
            
            
        }
        // Purposely not optimized for clarity

The idea is to eliminate one-by-one the segments from the rope until only the player and the rapel-point remains. 

I haven't tested it thoroughly, but so far it satisfied my basic needs. I'm hoping that someone will post a better and more flexible solution.