Oscillate object with forces/velocity

I want to oscillate my GameObject in a wave like form for it to appear floating.
Now this works fine when I manipulate position manually using Mathf.Sin, but since that doesn’t really play nice with collisions I’d like to do it with oscillating the force applied to the object, or even just velocity.

However, every time I try this in some form with adding forces, the object moves up, then pauses, then keeps moving up, (seems like velocity pingponging to 0 rather than oscillating from -foo to +foo)
I got to my force formula by taking the 2nd derivative of the position formula and multiplying by mass. I checked wolfram and it seems like my derivatives are correct.

This is driving me crazy. is my math wrong or my code?

Forces version (doesn’t work, just keeps going up)

void FixedUpdate()
{
    t += Time.fixedDeltaTime;
    float magnitude = rb.mass * (4*Pow(pi,2)/90)* Sin((t/3)*2* pi);
    rb.AddForce(magnitude * Vector2.up);
}

Velocity version (oscillates but slowly moves downwards)

   void FixedUpdate()
    {
        t += Time.fixedDeltaTime;
        float magnitude = 2*pi/30 *Cos((t / 3) * 2 * pi);
        rb.velocity += magnitude * Vector2.up;
    }

Position version- works perfectly

    void FixedUpdate()
    {
        t += Time.fixedDeltaTime;
        float magnitude = 0.1f * Sin((t / 3) * 2 * pi);
        Vector3 newPos = transform.position;
        newPos.y += magnitude;
        transform.position = newPos;
    }

Notes:

  • t is a time counter, rb is the RigidBody2D component, Sin/Cos/Pow are wrappers for Mathf functions

  • my object has a RigidBody2D attached with gravity scale set to 0, mass set to 1 (tried auto mass, didn’t seem to affect behavior).

  • force formula derivation:

     Pos(t)= 0.1*sin((t/3) *2pi)
     V(t) = Pos'(t) = (2pi/30)cos((t/3)*2pi)
     F(t) = m * a(t)
     F(t) = m * V'(t)
     F(t) = -m *(4pi^2/90)sin((t/3)*2pi)
    

also I tried this in various ways in Update using Time.deltatime and with Lerp. no dice.

Any help would be really appreciated :slight_smile:

If you have a position you want a Rigidbody2D to move to then simply use MovePosition (you should never set the Transform position with a Rigidbody2D attached as adding a Rigidbody2D is asking Unity to give it control of the Transform). This calculates the velocity required to move to the specified position during the next fixed-update. Note that this doesn’t alter the body velocity that you see via scripts at all; it’ll have the same velocity after it has moved as it did before it moved. Because the body is moving under its own velocity, it’ll detect collisions (especially continuous ones) correctly. Technically this is most useful for Kinematic body types however it does work for Dynamic body types as well.

Without reading any of your code, if I were scripting this, I’d let Unity handle most of the hard work. First, I would allow Gravity to pull my GameObject. My code would look like this:

Update () {
     if (transform.position < minHeight) {
          //AddUpwardsForce
     }
}

This would keep pushing the GameObject up when it fell below X coordinates. I would adjust the oscillating speed by adjusting the object weight/ the force I apply to it.

Alternatively, I would change the Object’s position rather than use velocity or force. Using Velocity or force means that the object will move a bit before the next calculation can be preformed. So instead, I would first calculate the next position then add/subtract from it’s transform.position.y. This will mean that the object wouldn’t move unless you specifically told it to in your script, allowing you more control over it.