Best way to create a chain (rope)

Aug 24, 2008 at 1:09 AM
I've tried creating a chain rope by creating a series of circular bodies, and putting revolute joints between them.
This worked well enough on its own, but when I attached the chain to an object to move the object with it, funky things happen.

It seems as if revoluteJoints aren't strong enough to support the cursor dragging an object. Maybe, maybe not.

If there's a better way to create a rope-like object, then I'd appreciate any direction, thank you.
Coordinator
Aug 24, 2008 at 2:11 AM
Have you tried the chain from the demoes?

I'm using a rope based on the demo where I switched the springs to revolute joints. I have not had any problems with it, but that might be because I attached the end of the rope to the moving object with a spring.

This is the code for my rectangle revolute rope. It's only for inspiration, if you want to use it, you might want to change it a little to suit your needs.

[CODE START]
    public class RevoluteRectangleRope : IPhysicsItem
    {
        private const float _layer = 0.1f;
        private Body[] _rectangleBodies;
        private Geom[] _rectangleGeoms;
        private Texture2D _rectangleTexture;
        private RevoluteJoint[] _revoluteJoints;

        public RevoluteRectangleRope()
        {
            RectangleMass = 1;
            RectangleHeight = 20;
            RectangleWidth = 20;
            RectangleCount = 10;
            Color = Color.LightGray;
            BorderColor = Color.Black;
            ChainOffsetLength = 25;
        }

        public Body FirstBody
        {
            get { return _rectangleBodies[0]; }
            set { _rectangleBodies[0] = value; }
        }

        public Body LastBody
        {
            get { return _rectangleBodies[_rectangleBodies.Length - 1]; }
            set { _rectangleBodies[_rectangleBodies.Length - 1] = value; }
        }

        public Vector2 Position { get; set; }
        public int RectangleCount { get; set; }
        public int RectangleWidth { get; set; }
        public int RectangleHeight { get; set; }
        public float RectangleMass { get; set; }
        public int CollisionGroup { get; set; }
        public Color Color { get; set; }
        public Color BorderColor { get; set; }
        public int ChainOffsetLength { get; set; }

        #region IPhysicsItem Members

        public void Load(ScreenManager screenManager)
        {
            _rectangleTexture = DrawingHelper.CreateRectangleTexture(screenManager.GraphicsDevice, RectangleWidth,
                                                                     RectangleHeight, Color, BorderColor);

            _rectangleBodies = new Body[RectangleCount];

            //Create the first body
            _rectangleBodies[0] = BodyFactory.Instance.CreateRectangleBody(screenManager.PhysicsSimulator,
                                                                           RectangleWidth, RectangleHeight,
                                                                           RectangleMass);
            _rectangleBodies[0].Position = Position;

            //Create the rest of the bodies
            for (int i = 1; i < _rectangleBodies.Length; i++)
            {
                _rectangleBodies[i] = BodyFactory.Instance.CreateBody(screenManager.PhysicsSimulator,
                                                                      _rectangleBodies[0]);
                _rectangleBodies[i].Position = _rectangleBodies[i - 1].Position + new Vector2(0, ChainOffsetLength);
            }

            _rectangleGeoms = new Geom[RectangleCount];
            _rectangleGeoms[0] = GeomFactory.Instance.CreateRectangleGeom(screenManager.PhysicsSimulator,
                                                                          _rectangleBodies[0],
                                                                          RectangleWidth, RectangleHeight);
            _rectangleGeoms[0].CollisionGroup = CollisionGroup;

            for (int j = 1; j < _rectangleGeoms.Length; j++)
            {
                _rectangleGeoms[j] = GeomFactory.Instance.CreateGeom(screenManager.PhysicsSimulator, _rectangleBodies[j],
                                                                     _rectangleGeoms[0]);
            }

            _revoluteJoints = new RevoluteJoint[RectangleCount];

            for (int k = 1; k < _revoluteJoints.Length; k++)
            {
                _revoluteJoints[k] = new RevoluteJoint(_rectangleGeoms[k].Body, _rectangleGeoms[k - 1].Body,
                                                       (_rectangleGeoms[k].Body.Position +
                                                        _rectangleGeoms[k - 1].Body.Position)/2);
                _revoluteJoints[k].Softness = 0.0f; // 0.0f
                screenManager.PhysicsSimulator.Add(_revoluteJoints[k]);
            }
        }

        public void Unload(PhysicsSimulator physicsSimulator)
        {
            foreach (Body body in _rectangleBodies)
            {
                body.Enabled = false;
                physicsSimulator.Remove(body);
            }

            foreach (Geom geom in _rectangleGeoms)
            {
                physicsSimulator.Remove(geom);
            }

            foreach (RevoluteJoint joint in _revoluteJoints)
            {
                physicsSimulator.Remove(joint);
            }

            _rectangleTexture = null;
        }

        #endregion

        public void Draw(SpriteBatch spriteBatch)
        {
            for (int i = 0; i < _rectangleGeoms.Length; i++)
            {
                spriteBatch.Draw(_rectangleTexture, _rectangleGeoms[i].Position, null, Color.White,
                                 _rectangleGeoms[i].Rotation,
                                 new Vector2(_rectangleTexture.Width/2, _rectangleTexture.Height/2), 1,
                                 SpriteEffects.None, _layer);
            }
        }
    }
[CODE END]
Aug 25, 2008 at 1:27 PM
Thanks.
I never noticed that demo in the QuickStart.