Swinging physics

Hello, I’m currently working on rope swinging physics for a 2d game, and I’ve got it to work somewhat but I can’t seem to get it to behave quite right. The player is affected by gravity and creates an arc as expected, but loses momentum just past the bottom of the arc. Thinking about it, it makes sense since gravity is still acting on the player, preventing more progress along the arc. But not once in all the articles I’ve read on implementing swinging physics was this mentioned, which makes me think this isn’t expected behavior.

I don’t expect the player to always be able to make a full semicircle (or more), but I’d like it to at least get significantly past the bottom of the swing with some ease. Here’s a pic to better show what I mean:

http://s32.postimg.org/3ua992zph/help.png

Here’s the relevant code:

private static final double FRICTION = 0.95d;
private static final double GRAVITY  = -9.8d;

private void applyForces()
{
    velX = (posX - prevPosX) * FRICTION;
    velY = (posY - prevPosY) * FRICTION;

    prevPosX = posX;
    prevPosY = posY;

    // currently, accX and accY increase only due to gravity or user input
    accY += GRAVITY;

    posX += velX + accX;
    posY += velY + accY;

    accX = 0.0d;
    accY = 0.0d;
}

private void enforceConstraints()
{
    // the anchor is the center point of the arc
    if (anchor != null)
    {
        double distX = posX - anchor.getPosX();
        double distY = posY - anchor.getPosY();
        double distSq = distX * distX + distY * distY;
        if (distSq > anchor.getMaxDistSq())
        {
            // is there a better way to pull the player back in? my math's pretty rusty
            double scale = anchor.getMaxDistSq() / distSq;
            posX = anchor.getPosX() + (distX * scale);
            posY = anchor.getPosY() + (distY * scale);
        }
    }
}

I’m using fixed time steps here, every update is a full step forward and there are no delta time values to be passed.

I’ve tried playing around with some values to get it right, but it’s never quite there. Changing the gravity doesn’t really do much; The player speeds up or slows down but still doesn’t make it to a full semicircle. Lessening the friction helps a bit, but the player ends up sliding around a lot once out of the swing. I think I’m missing some piece of code to make it behave as I want it to. Any tips would be appreciated.

Many people use physics engines like box2d to handle stuff like this which will be easier to implement, but if you want to try to do it yourself read on.

It looks like you are losing momentum in your method of enforcing the rope length constraint. Instead of just moving the character back to within the rope length distance you should break down the movement phase so you allow the portion of the player movement that is within the rope’s reach using the normal movement code and then when the rope is tight you have to breakdown the force acting on the player and the velocity of the player into a component that is parallel to the rope (moving directly away from the anchor point) and a component that is perpendicular to the rope. The parallel component just goes away unless you want to model a stretchy rope. Imagine if someone is dropped directly down from the anchor point to see that this parallel component should not influence the swing. The perpendicular component will propel the character along the circular path of the rope’s reach. I believe you can just model this like angular velocity as long as the rope is tight to avoid the losses you will get from trying to recalc it every discrete physics step. So that means that if the rope is tight you should calculate how far the character would move in a straight line during the timestep using this ropePerpendicularVelocity, but then don’t move them in a straight line instead move them that distance along the circumference of the circle that the rope length creates around the anchor point. Remember when the player lets go of the rope or the rope is no longer tight because some other force acted on the player to convert the ropePerpendicularVelocity back into a normal world velocity vector. And remember each physics step to keep applying the component of the gravity force that is perpendicular to the rope so that it alters the ropePerpendicularVelocity.

In order to make it easier to do these calculations you will probably want to use a vector class/library instead of keeping track of the x and y components of forces and velocities separately.