Sine-wave acceleration problem


I’m trying to make my rigidbody float above the ground in a sinusoidal fashion. What’s important, is that I don’t want to move it directly via transform or velocity, but by applying a continuous, changing force.
Funny thing is - it actually works correctly in both of the aforementioned cases, but not in the desired one.

The results are not-that-bad - the movement is smooth and all, but - first of all - it’s way too subtle. Secondly, the preset amplitude and frequency seem not to affect it the way they should.

A word about implementation. I’ve followed the sine wave equation, starting at:



  • A - amplitude
  • f - frequency
  • t - time; in code get’s replaced by Time.time

Now, since I want AddForce to do the dirty work, I need to find the acceleration formula. So, I’m finding the second derivative (with respect to t) of the first equation:

So it’s almost set.

However, I do realize that in Unity I cannot affect the acceleration (or force) by directly setting its level - all I can do is add some in a certain direction.

That’s exactly how I went about it:

var difference = newAccel - lastAccel;
rb.AddForce(difference, ForceMode.Acceleration);

Finally, here’s the complete code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Forcer : MonoBehaviour {

    float _frequency;
    float Frequency { get { return _frequency; } set { _frequency = value; } }

    float _amplitude;
    float Amplitude { get { return _amplitude; } set { _amplitude = value; } }

    Rigidbody ThisBody { get; set; }

    Vector3 LastSetAcceleration{ get; set; }

    void Awake()
        ThisBody = GetComponent<Rigidbody>();             
    void Start()
        LastSetAcceleration =;

    void OnEnable()
        ThisBody.useGravity = false;    
    void OnDisable()
        ThisBody.useGravity = true;    

    void FixedUpdate()
        var desiredAccelerationValue = -4 * Amplitude * Mathf.Pow(Mathf.PI, 2) * Mathf.Pow(Frequency, 2) * Mathf.Sin(2 * Mathf.PI * Frequency * Time.fixedTime);
        var desiredAcceleration = desiredAccelerationValue * Vector3.up;

        var difference = desiredAcceleration - LastSetAcceleration;

        ThisBody.AddForce(difference, ForceMode.Acceleration);

        LastSetAcceleration = desiredAcceleration;    

NOTE: UseGravity is disabled by default, the code implementation is redundant at the moment.

Summing up - my question is: why on earth do velocity and disposition equations work whereas adding acceleration results in some bizarre behaviour? Where do I make that crucial mistake?

All help’s appreciated! Thanks in advance :wink:

I know it’s an old question, but i still had your question open (besides 500 others).

Well, your main issue is this:

var difference = desiredAcceleration - LastSetAcceleration;
ThisBody.AddForce(difference, ForceMode.Acceleration);

Why do you calculate the difference between the last acceleration and the current one? That’s like manually calculating another derivative on top of your 2. So you end up using the 3rd derivative. Your formula caculates the exact acceleration you need at a certain point in time. So just apply your “desiredAcceleration” as acceleration

Keep in mind that your rigidbody starts with an initial state without any velocity. At time 0 the velocity should be max as the position sine is the steepest at this point. Though that means that the second derivative will be 0 at time 0 and will decrease downwards. So your velocity will get more negative during the first half wave. This was originally meant to bring the velocity back down to 0 at 90°. However since our initial velocity is not +max we only get a movement downwards from the starting position. Keep in mind that applying the acceleration to the velocity is actually integrating the acceleration. And applying the velocity to the position is actually integrating the velocity. What you’re missing when integrating is the arbitrary constant which in our case represents the initial state. So you may want to calculate the initial velocity at start using the first derivative multiplied by Vector3.up.

Apart from that it should be clear that you never get a stable movement or velocity as you integrating the acceleration over time to produce the velocity and you integrate the velocity to produce the position. However since this integration happens at discrete time steps and not continuously and it’s unlikely that your frequency matches a multiple of the fixedupdate rate your velocity and position may drift over time. Further more since floating point values have a limited precision which also changes depending on the magnitude of the value your values will drift even more. If that potential drift is actually wanted or small enough to not care it should work with the changes i’ve mentioned above.