So I'm trying to simulate orbital mechanics in Unity 2D. I have a ship and Moon model in scene. I calculated the sphere of influence, and if the distance between the Moon and ship is smaller than sphere of influence, the gravity will effect. Problem is;
I can't get gravity affect working.
I've tried using AddForce method, but since it requires Vector2 elements and I calculate my force as float (I use Newton's law of gravitation formula and I get a float), I don't know how to include my float force in Vector2 force.
force = (GravitationalConstant * ((planetMass * ship.GetComponent<Rigidbody2D>().mass)/Mathf.Pow(Vector3.Distance(ship.transform.position,transform.position),2)))/(realityConstant * forceReducer);
if (Vector3.Distance(transform.position,ship.transform.position) < SOI/realityConstant){
ship.GetComponent<Rigidbody2D>().AddForce(new Vector2((float)force,0f));
}
This code makes Moon pull the ship to itself only from left side. When ship passes Moon, it keeps pushing it to right. Not to itself.
I need a fix, that makes Moon pull the ship to itself everytime, with a specific force. How do i make this happen?
Any idea would be helpful.
Thanks a lot!
Force is applied using a vector. You have the magnitude of your vector but not its direction. You can calculate a direction by subtracting moon position from the ship position:
ship.GetComponent<Rigidbody2D>().AddForce((Moon.transform.position -
ship.transform.position).normalize * force);
Related
I'm trying to make a pick up objects mechanic like the one in Amnesia. It's easy to calculate needed rigidbody's velocity, so that the held object stays in front of camera, but my problem is that the object doesn't rotate at all when I hold it. And I would rather have it always be rotated towards the camera. This could easily be achieved with simply parenting the object to player's camera, but...
The behaviour I'm after is as follows: if the bottle I picked up was standing on a table, with neck of the bottle facing ceiling, I would like to see this bottle always with its neck facing ceiling while I hold it. But if this bottle collides with something, it should behave like it actually bumped onto something, so it should rotate some small amount, but it should always try to return to its "original" rotation (in this case, neck facing ceiling).
I think that I need to calculate angular velocity for that and probably have some lerp to return to original rotation, but I'm at a loss on how to do that properly.
I think that the first thing I would need to do is to store the initial direction the moment player picks object up:
Vector3 targetDirection = playerCamera.transform.position - transform.position;
Script is on the held object, so "transform" refers to it. In FixedUpdate() I probably need to have some interpolation, so that angular velocity always tries to rotate the object to original rotation:
rigidbody.angularVelocity = Vector3.Lerp(rigidbody.angularVelocity, targetAngularVelocity, lerpSpeed * Time.fixedDeltaTime);
I don't know how to calculate targetAngularVelocity, because after all I would like the held object to return to original rotation smoothly. I'm not even sure if that's the right way to do this thing and perhaps I should do something else than to calculate angular velocity needed to rotate object properly. I tried just interpolating localRotation to original local rotation, but that did not allow the held object to bump on stuff (the movement then was very jittery). Any ideas?
You need a stabilizer. A script which will add torque/angular velocity to the object, whose angle is different from the target one. Say, you have two variables: targetDirection and currentDirection aka transform.forward. Then you write something like this in fixed update:
var rotation = Quaternion.FromToRotation(currentDirection, targetDirection).eulerAngles * sensitivity;
rigidbody.angularVelocity = rotation;
I recommend to set sensitivity about 0.05 and then increase it if the object stabilizes too slow.
Probably I confused the order, so you should put minus somewhere, but the approach itself is applicable.
What i'm looking to do is something similar to our solar system, where you are gravitically drawn to one planet till you leave it's pull, and then once you're on another planet be drawn to that gravity.
I have found many entries online about how to create gravity for a single planet, but none i've found work for multiple sources.
Any help would be GREATLY appreciated.
Projects I've already looked at were mainly for single planet gravity.
unity 3.3, create local gravity on object
http://answers.unity3d.com/questions/13639/how-do-i-make-a-small-planet-with-gravitational-pu.html
http://answers.unity3d.com/questions/701618/how-could-i-simulate-planetary-gravity-that-has-an.html
This could be done easily by adding a normal force relative to the planet on the surrounding objects.
According to physics of Universal gravitational force you can calculate the gravitational force. Then calculated the normal force at the moment and add the force.
void FixedUpdate(){
// Do the Force calculation (refer universal gravitation for more info)
// Use numbers to adjust force, distance will be changing over time!
forceSun = G x (massPlanet x massSun)/d^2;
// Find the Normal direction
Vector3 normalDirectionSun = (planet.position - sun.position).normalized;
// calculate the force on the object from the planet
Vector3 normalForceSun = normalDirection * forceSun;
// Calculate for the other systems on your solar system similarly
// Apply all these forces on current planet's rigidbody
// Apply the force on the rigid body of the surrounding object/s
rigidbody.AddForce(normalForceSun);
// .... add forces of other objects.
}
With various m1, m2 values you will be able to make the system more realistic. As an example make the object move/accelerate towards the planets with higher mass.
How does SpriteKit's physics engine (Box2d) move bodies and apply gravity to them?
is it just the standard:
velocity = velocity + gravity
position = position + velocity * deltaTime
or is there a more complex equation.
I ask this because I am trying to calculate the trajectory of the body and plot it.
Simplified, this is correct. However there can be other forces acting on a body (collisions, joints) and thresholds (ie stop moving if velocity below threshold, etc) and floating point rounding errors can add up.
So if you're looking for a forward calculation it depends on how precise it needs to be.
The most precise option would be to actually run the simulation to advance it to see where bodies will be - however since SK doesn't give you the Box2D sources this can't be done, ie you can't copy the world state and advance it manually in a copy of the current world.
I'm making a 2D game in unity and I'm stuck. I have a rigidbody2d projectile that is fired based on the click position. I want to make this projectile faster without changing its trajectory or changing the timescale of the entire world and I cant change the gravity scale. Any ideas ? Thank you in advance :)
give the object less mass, for one. But if you are using a Vector for velocity so.
Where ever you are setting the velocity of the bullet in the script, add this (in JavaScript)
var speed = 2.5; // or what ever you want it to be, play with it
// as long as you multiply both x and y the same, they will keep their direction.
gameObject.rigidbody2D.velocity.x *= speed;
gameObject.rigidbody2D.velocity.y *= speed;
I have a ball that you blow on with air. I want the ball to be blown more if it is close to the blower and blown less if it is farther away from the blower. I am using box2d and I am using the impulse function."body->ApplyLinearImpulse(force, body->GetPosition())". I can't seem to find a formula or a way to accomplish this. If I want the ball to blow to a total distance of 300 pixels right, how could I accomplish this? Please help.
If you want to calculate the distance before simulation you have to take a look at box2d sources. When simulating the velocity of the body is modified according to gravity, extra applied forces, linear damping, angular damping and possibly something more. Also velocity relies on velocity iterations.
But I think if you want a really smooth motion (like from a blow) you'd better use applyForce function instead of impulse. But be sure you are applying the force each simulation step.
EDIT:
Also you can simulate the air resistance as:
Fa = -k*V*V. I've simulated movement in the pipe this way. Worked great.
So each step you can make something like this:
BlowForce = k1 / distance; // k1 - coefficient
Resistance = -k2 * V * V; //k2 - another coefficient
TotalForce = BlowForce + Resistance;
body->ApplyForce(TotalForce);
I am not a box 2d expert but what i would do is create a small box which is actually invisible and let the ball hit the box...if the blower is blowing more i would give more speed to the box in opposite direction. As far as 300 pixel length is concerned you have to adjust the forces and velocity such that the ball goes
300/<your_rendering_window_to_physics_world_ratio>
in physical world.
Force = mass * acceleration, so take the mass you set your body to, calculate the acceleration you want (remember to divide 300px by PTM_RATIO) and then multiply the two together.