Custom gravity + trajectory prediction........ omgwtf

edited in Questions and Answers
Hi guys

I have a weird problem... I need to make a trajectory prediction line for a physics object, but that gravity is not as linear or simple as Unity's 9.81 downwards. It's a trajectory towards an object, and it's, uh, complicated:

This is in Update() (I used FixedUpdate() at first, but I changed it to Update for performance, but the deltaTime makes it wonky so I think I'm going to go back to FixedUpdate() )

// first work out a normalised direction from planets[i].transform.position towards gravity centre (_home)
normalisedForce = (_home.transform.position - planets[i].transform.position).normalized;

// apply gravity towards centre using normalisedForce and deltaTime and some tweaks to get the desired feel, affected by the scale of the object
planets[i]._rb.AddForce((normalisedForce * Time.deltaTime * gravityMultiplier * 80) + ((normalisedForce * 20f )/ planets[i].transform.localScale.x));

// clamp to a max velocity, which is also affected by the scale of the object
planets[i]._rb.velocity = Vector2.ClampMagnitude(planets[i]._rb.velocity, planets[i].maxSpeed);


Then I use the same code to try and do a for do loop that takes the current velocity of the object, and steps through 100 steps to work out a trajectory. But it always come out wrong. Not sure if it's completely wrong or just subtly wrong.

The problem *seems to* be that I don't know how to relate the running velocity of an object to this weird calculation that I run to addForce to get a gravity that feels the way I want it to. Also it's not reliant on time.

for (int i = 1; i < 100; i++)
			{


				Vector2 normalisedForce = (_home.transform.position - nextPosition).normalized;
				Vector2 nextForce = turnMultiplier * ((normalisedForce * _gc.gravityMultiplier * 80) + ((normalisedForce * 20 )/ transform.localScale.x));
				nextPosition += velocity + new Vector3(nextForce.x, nextForce.y, 0);
				orbitLine.SetPosition(i, nextPosition);


I was trying to tweak turnMultiplier to see if I can get to a value where the line doesn't go crazy or way underaffected. A value of 0.0099 gives me this...... Which is better than what it was but not "right" either...

image

turnMultiplier of 0.095 gives me this :P

image

Am I actually on the right track or am I completely wrong? How come it's kinda half right but doesn't resolve correctly after a certain point?

Comments

  • edited
    //gets a gravity vector at point AP in 3d space.
    Vector3d GetGravityVector(Vector3d AP)
        {      
            Vector3d g = Vector3d.Zero;
            double G = 6.67191e-11;  //universal gravitational constant
           APMass = 1;
    
          foreach (MAstroBody b in Bodies)
          {
            Vector3d delta = (b.Position - AP).Normalized(); 
            double force = G * ((APMAss * b.Mass) / (b.DistanceToAvatar * b.DistanceToAvatar));
            g += delta  * force;
          }
    
         //And Voila, we end up with 9.8m/s acceleration on Earth, and 1.6 on the Moon.
          return g;
        }
    
    //now for each future point * the current force
    Vector3d CurrentForce;
      for ( int i=0; i< 100; i++ ){
      Vector3d nextpos = Currentpos* GetGravityVector(g) * CurrentForce;
      and plot the graph...
      CurrentPos = nextpos;
    }
  • @John thanks for your input, my actual main problem isn't the gravity equation, but more the trajectory prediction line... Any thoughts on how to implement that?
  • I see you note you haven't incorporated time. That seems like a fundamental problem. Maybe try bringing it into the process somewhere like:

    position += velocity * time


    You'll need time to be a sensible timestep. If you use something like 0.01667 then this basically match up with 60 FPS of normal execution. You can then decide the total time to simulate for. Currently it's like you're simulating in 1 second step, which are huge, so you get weird physics things happening cause forces are not properly integrated over the path.

    Then, I'm not sure exactly what `RigidBody.AddForce()` does, but I doubt it's just adding itself to the position (like you do in your snippet). If you're using `AddForce()` in your calcs, then you'll want to try do something the same in your projection simulation. Time will also need to be factored into this. If you can't manage to get them to match up, maybe consider replacing `AddForce()` with something that makes more sense to you?
  • edited
    You will definitely need to account for time and adjust velocity as francoisvn says. Take force Force = mass * acceleration;
    And the velocity of an object after a certain time is its starting velocity and its acceleration over that time. So velocity=v0 + acceleration*time;
    Some substition gives: v = v0 + F/m * t;
    Which when applying in a loop I think can become: v += F/m * t;

    So I think take out the turnModifier and try this:

    Vector2 nextVelocity=rb.velocity;//grab initial velocity from your rigidbody.
    //I assume nextPosition used below is already grabbing the starting position before the loop as well
    for (int i = 1; i < 100; i++)
    			{
    				Vector2 normalisedForce = (_home.transform.position - nextPosition).normalized;
                    		//below Time.deltaTime might give close results, but due to its nature it might be off since it will change in future frames
                    	       //Changing this and the other instance of it in the force formula to fixedDeltaTime should make it reliable
    				Vector2 nextForce = (normalisedForce * Time.deltaTime * _gc.gravityMultiplier * 80) + ((normalisedForce * 20 )/ transform.localScale.x);
                    		nextVelocity += (nextForce * Time.deltaTime)/rb.mass; //(F/m) * t -> Ft/m perhaps you can't multiply in the t. maths is rusty, so adjust if needed
    				//set next position to current and offset with velocity
    				nextPosition += nextVelocity;
    				orbitLine.SetPosition(i, nextPosition);
                }
  • @Tuism, random idea, and obviously might not work for your game, depending upon gameplay, but what if you create a proxy object for your physics and then store a buffer containing the positions that this proxy object went through, and then you render the visible object and trajectory a few physics steps behind?
Sign In or Register to comment.