How to code forces so that they are applied in an accelerating type of way.

Okay, so I am trying to code an object in 3D to move however I want it to move in that 3D space.

For example, make it move along a certain path and also for a certain amount of time.

This is my attempt at trying to do this:

using UnityEngine;
using System.Collections;
public class Motion : MonoBehaviour
{
    void Start()
    {
      

        StartCoroutine(Process());
      
    }



    private IEnumerator Process()
    {
      
        yield return StartCoroutine(GoForward(0, 2));
        yield return StartCoroutine(GoForward(1500, 7));
        yield return StartCoroutine(GoForward(500, 3));
        StartCoroutine(GoRight(100, 4));
        yield return StartCoroutine(GoForward(500, 4));
        yield return StartCoroutine(GoForward(1000, 5));
        StartCoroutine(GoLeft(100, 3));
        yield return StartCoroutine(GoForward(1000, 3));
        yield return StartCoroutine(GoForward(1500, 13));
        StartCoroutine(GoLeft(100, 2));
        yield return StartCoroutine(GoForward(1000, 2));
        yield return StartCoroutine(GoForward(1500, 6));
        StartCoroutine(GoLeft(100, 2));
        yield return StartCoroutine(GoForward(100, 2));
        StartCoroutine(GoRight(100, 2));
        yield return StartCoroutine(GoForward(100, 2));
        StartCoroutine(GoLeft(50, 2));
        yield return StartCoroutine(GoForward(100, 2));
        yield return StartCoroutine(GoForward(100, 4));
        StartCoroutine(GoRight(100, 2));
        yield return StartCoroutine(GoForward(100, 2));
        StartCoroutine(GoLeft(100, 2));
        yield return StartCoroutine(GoForward(100, 2));
        StartCoroutine(GoRight(100, 2));
        yield return StartCoroutine(GoForward(100, 2));
        yield return StartCoroutine(GoForward(150, 5));
        yield return StartCoroutine(GoForward(50, 2));
     

    }

    IEnumerator GoForward(int strength, float time)
    {
      
        GetComponent<Rigidbody>().AddForce(Vector3.forward * strength); //Adding Force ; Starts
      
        yield return new WaitForSeconds(time);
      
        GetComponent<Rigidbody>().AddForce(Vector3.back * strength);  //Removes Force ; Stops
    }

    IEnumerator GoBack(int strength, float time)
    {
        GetComponent<Rigidbody>().AddForce(Vector3.back * strength); //Adding Force ; Starts

        yield return new WaitForSeconds(time);

        GetComponent<Rigidbody>().AddForce(Vector3.forward * strength);  //Removes Force ; Stops
    }

    IEnumerator GoUp(int strength, float time)
    {
        GetComponent<Rigidbody>().AddForce(Vector3.up * strength); //Adding Force ; Starts

        yield return new WaitForSeconds(time);

        GetComponent<Rigidbody>().AddForce(Vector3.down * strength);  //Removes Force ; Stops
    }

    IEnumerator GoDown(int strength, float time)
    {
        GetComponent<Rigidbody>().AddForce(Vector3.down * strength); //Adding Force ; Starts

        yield return new WaitForSeconds(time);

        GetComponent<Rigidbody>().AddForce(Vector3.up * strength);  //Removes Force ; Stops
    }

    IEnumerator GoLeft(int strength, float time)
    {
        GetComponent<Rigidbody>().AddForce(Vector3.left * strength); //Adding Force ; Starts

        yield return new WaitForSeconds(time);

        GetComponent<Rigidbody>().AddForce(Vector3.right * strength);  //Removes Force ; Stops
    }

    IEnumerator GoRight(int strength, float time)
    {
        GetComponent<Rigidbody>().AddForce(Vector3.right * strength); //Adding Force ; Starts

        yield return new WaitForSeconds(time);

        GetComponent<Rigidbody>().AddForce(Vector3.left * strength);  //Removes Force ; Stops
    }

}

Essentially, this kinda works. This lets me move my object in a certain direction for x amount of time (in seconds) and an arbitrary strength. However, my issue with my implementation is that the force gets applied once each time it is called and looks more like a jolt, and not very smooth. So what I’d like to make it look more like is like a continuous force that is applied for x amount of time.

So right now, it is more like GoForward looks like it impulses Forward only once but what I want is that it continuously impulses Forward for the allotted time. Does anyone think they can figure out how I could implement this?

Please use code tags. I didn’t even look over your code…

It’s a bad idea to do physics related processing inside a coroutine. Because a coroutine runs at the same frequency as Update and any physics processing should be done in FixedUpdate. That’s probably the reason why you’ve got a not smooth movement.

That makes sense. I think I initially tried with fixed update, but then I wasn’t sure how to only apply a force for an x amount of time. So then my object wouldn’t move in a path-like manner but all the forces would be applied simultaneously

I see. But I’m not quiet sure whether you have a good approach.
What are you trying to do? If you know the path, why don’t you simply animate the object to follow that path? More by using kinematics rather than using dynamics?

Basically, I have a motion simulator that extracts the telemetry from an object and then the simulator will move according to that. How would I go about animating the object to follow the path/using kinematics? That may work, I’m just not sure exactly how to go about implementing it either.

What kind of data do you have as input?

  • Do you have the object trajectory (positions in time).
  • Or some accelerometer and gyro data.

I have the object trajectory

Then you can use kinematics. If you know the position in time, you know the position at any given time. In your case you want to know the position at the current time. Dependending on your sampling rate, you might need to interpolate in the case your data is too sparse to obtain smooth movement.

I think you should just have a Vector3 function for this rather than the strange beast you’ve cooked up. It’s awfully strange code that you could probably shrink down to a handful.

Right, is there an example of doing that? (Originally I tried that but couldn’t figure out how to code it)

Perhaps something like this:

animatedObject.transform.position= TrajectoryData[timeindex]; //Where Trajectory data is an array of Vector3's.

Edit:
This does assume that you have enough trajectory data to make smooth animations. If not, you will need to do as Eric suggested, and animate the transition between an object’s consecutive trajectory points. I would suggest using the Vector3.Lerp function for that, (though I would still simply assign the result to the animatedObject.transform.position).

1 Like

Okay, I will try that. I am thinking of creating a script that records joystick input to create any kind of trajectory I want to for my object to follow. How will I know if my data will be good for using the animatedObject versus using Lerp to interpolate between the points?

It would me simpler to directly edit the path you want your object to follow.

If you have enough point, the object would move smoothly, that would be if your sample rate is about 60fps. If your sample rate is lower than that, then the object might seems to make little jumps instead of moving continuously. That would also depend on the speed your object is moving.

By edit the path, do you mean there is an easy way to create paths for my object to follow? As of now, I’ve tried either using data points in (x,y,z) or my attempt from my original post with the forces. So, I was going to make trajectories by recording data points from a joystick. I’ll research paths as well to see where that takes me then.

I do have many many points so then I should be fine on that end of things.

I would think using a joystick, or mouse is a FAR better way to get lots of points stored in the system, at least as opposed to typing them in!
One consideration: if you record your points at a particular time interval, you will have more points at a given coordinate if you stop moving the input device for a second or two. Instead, you may wish to consider recording a point, once the input has moved some constant distance. This would allow objects moving on the previously recorded path, to move at some constant velocity, rather than the speed of your inconsistent human-input.
Edit: another way to deal with this (and reduce data), would be to only record a point when you hit a particular key or button. You can make long straight runs with just two point like this, but it would REQUIRE you use the Lerp/interpolation discussed previously.

I’m having trouble figuring out how to implement this.

animatedObject.transform.position= TrajectoryData[timeindex];

I’m not sure how I can call this in the right manner. Should I use coroutines to move it appropriately with respect to time passed. Since I think iterating through it in Start or Update won’t work the right way.

Also, since I have so many datapoints, what is the best way to instantiate the TrajectoryData array? If i place in all the points i’ll have thousands of line with just data points. (which im ok with but in case there is a better way, is why i ask)

OK, first, forget about coroutines. They are not necessary for this and they have already led you into shark-infested waters.

Next, you seem uncertain where to get the time index. That’s easy: Time.time (or, perhaps, Time.time - startTime, if your animation doesn’t start at time 0). Add a bit of math if your index is not in seconds, for example, multiply by 60 if you’ve got 60 samples per second. Something like this:

public class PathMover : Monobehaviour {
    public Vector3[] TrajectoryData;   // which you get... somewhere

    float startTime;

    void Start() {
        startTime = Time.time;
    }

    void Update() {
        int index = Mathf.FloorToInt((Time.time - startTime) * 60);
        transform.position = TrajectoryData[index];
    }
}

Keep it simple! Now you just have to deal with the bigger problem of, where do you get that trajectory data?

1 Like

Awesome, definitely getting close to intended result.

Still have an issue however. Essentially, even though I have a lot of data points, my simulator gives me jittery motion when moving and I think it is because this is “jumping” from point to point rather than moving continuously.
I thought about maybe using Lerp, but I think the same issue may occur. Is there a way to go from point to point in a continuous fashion?

I was looking at transform.Translate as well. Does this moving along x, y, z continuously or is it resetting the position similar to transform.position?

Setting transform.position and calling transform.Translate do exactly the same thing.

And yes, this code jumps from point to point. If you don’t have enough points to cover every frame (typically 60 fps), then the motion won’t look as smooth as it should. Using Lerp would indeed be the correct way to compensate for that.

(If your points were very far apart then you might want to compute a spline curve between them, and move along that. But I suspect your points aren’t that far apart, in which case a simple linear interpolation ought to be fine.)