Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Help me troubleshoot my pendulum script?

Discussion in 'Scripting' started by m0nkeybl1tz, Jun 6, 2021.

  1. m0nkeybl1tz

    m0nkeybl1tz

    Joined:
    Feb 10, 2013
    Posts:
    25
    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:

    Code (CSharp):
    1.  
    2.     void FixedUpdate()
    3.     {
    4.         //force due to gravity
    5.         Vector3 gForce = gravity * Vector3.down;
    6.         //vector from grip point to current position
    7.         Vector3 offset = transform.position - gripPoint.position;
    8.         //get a normalized vector perpendicular to the offset (in the transform's forward direction)
    9.         Vector3 moveDirection = Vector3.Cross(offset, transform.right).normalized;
    10.  
    11.         //get the component vector of gravity in the move direction
    12.         Vector3 hForce = Vector3.Dot(gForce, moveDirection) * moveDirection;
    13.  
    14.         //calculate the velocity in the forward direction and use it to calculate the centripetal force on the object
    15.         float hVelocity = Vector3.Dot(velocity, moveDirection);
    16.         Vector3 vForce = -hVelocity * hVelocity * offset.normalized / offset.magnitude;
    17.  
    18.         //add the forward force and the centripetal force
    19.         Vector3 velocityDelta = (hForce + vForce) * Time.deltaTime;
    20.  
    21.         //add the acceleration to the current velocity
    22.         velocity += velocityDelta;
    23.  
    24.         //change position based on velocity
    25.         transform.position += velocity * Time.deltaTime;
    26.  
    27.     }
    28.  
    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?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,713
    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.
     
    Bunny83 likes this.
  3. m0nkeybl1tz

    m0nkeybl1tz

    Joined:
    Feb 10, 2013
    Posts:
    25
    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!
     
    Kurt-Dekker likes this.
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,713
    Or... just generate an angle with Sin:

    Code (csharp):
    1. float angle = MaxDeflectionInDegrees * Mathf.Sin( Time.time * RateOfSwing);
    And use that angle to rotate a pivot object above your pendulum:

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