Help me troubleshoot my pendulum script?

Hey all, I’m working on a game where a character can swing around a pole, and it’s important that it be physics based. Here’s what I’ve worked out so far:

    void FixedUpdate()
    {
        //force due to gravity
        Vector3 gForce = gravity * Vector3.down;
        //vector from grip point to current position
        Vector3 offset = transform.position - gripPoint.position;
        //get a normalized vector perpendicular to the offset (in the transform's forward direction)
        Vector3 moveDirection = Vector3.Cross(offset, transform.right).normalized;

        //get the component vector of gravity in the move direction
        Vector3 hForce = Vector3.Dot(gForce, moveDirection) * moveDirection;

        //calculate the velocity in the forward direction and use it to calculate the centripetal force on the object
        float hVelocity = Vector3.Dot(velocity, moveDirection);
        Vector3 vForce = -hVelocity * hVelocity * offset.normalized / offset.magnitude;

        //add the forward force and the centripetal force
        Vector3 velocityDelta = (hForce + vForce) * Time.deltaTime;

        //add the acceleration to the current velocity
        velocity += velocityDelta;

        //change position based on velocity
        transform.position += velocity * Time.deltaTime;

    }

It works for the most part, but the pendulum loses momentum, and slowly drops over time. I can manually keep it at the same distance, but it still loses momentum. Can anyone help me figure out if I’m doing something wrong? Or suggestions for a better way to do it?

Any discrete simulation is going to either gain or lose energy over time. This is because you’re simulating a continuous smooth motion with a series of linear steps, arrow straight between your samples.

You can minimize it by making the steps as small as possible, but that costs computations. You can fiddle and fudge with the variables to try and counter it, but at the end of the day, all computer physics simulate continuous quantities with discrete digital processes, in this case “frames.”

An alternate way to do simple harmonic motion is to just keep a time value constantly increasing and drive the pendulum swing angle with something like a Mathf.Sin() wave. But if you interrupt it (eg, bump it), it cannot handle anything like that easily.

1 Like

Ah I think you’re totally right. And I may look into doing the Sine, since I don’t plan on allowing interruptions, now I just need to remember the trig to calculate the angle in 3D space. Thanks!

1 Like

Or… just generate an angle with Sin:

float angle = MaxDeflectionInDegrees * Mathf.Sin( Time.time * RateOfSwing);

And use that angle to rotate a pivot object above your pendulum:

PendulumPivotTransform.localRotation = Quaternion.Euler( 0, 0, angle); // swing along Z axis