- Home /
How can I make a gravity field similar to a planetary body?
Hey guys, I'm trying to make a moving spherical 2D object that can pull objects in if they get caught in it's gravity field but in a way that if they're not already moving directly to it, and they come in on an angle, they will kind of veer off while being pulled in slightly and gain some speed.
I have tried the following script on my objects (the ones that will be getting manipulated by this gravity field), but I'd rather have a script on the gravity object itself to pull in the other objects if their Tag or Layer is what it's looking for:
if (insideGravity)
{
Vector3 gravityField = planet.transform.position - transform.position;
float index = (radius - gravityField.magnitude) / radius;
rb.AddForce(gravityAmount * gravityField * index);
}
That bool is set by OnTriggerEnter2D, but I'm open to any way to get it to detect when it's entered the radius.
And the issue I'm getting with the code above is that it will enter the trigger, and then go straight towards the planet and lock there, I need it to pick up that momentum and then kind of do a large orbit unless it exits the radius and then it should keep it's momentum until my drag value slows it back down to it's normal speed.
Also it should be noted that this is how I'm moving the objects that will be acted upon by this gravity field:
Vector2 movement = new Vector2(xDirection, yDirection).normalized;
rb.velocity = movement * moveSpeed;
I appreciate any and all help you are able to give me! Thank you!
If I understand what you want correctly, you should get a list of all objects that you want the gravity of the object to affect (with tags or a list that you create yourself), cycle through it and add a force to each rigidbody, if the distance between the "planet" or something and the object is smaller than the gravity field
Thanks for the response!
How can I get the distance exactly? I think I get the rest of it, but the distance factor is what's stumping me.
Also would I use OnTriggerEnter2D and get the tag from that? Or is there another way to do it without colliders/triggers?
The length of any Vector is calculated using the Pythagorean Theorem (same as the hypotenuse of a triangle). This applies to any number of dimensions, so the principle is identical for 2, 3, 4, and more dimensions.
// Vector between two points is B-A or A-B.
// i.e. (sourceVector - destinationVector) or vice versa
// Vector2 example
Vector2 AB = B - A; (or A - B, for a vector pointing in the opposite direction)
Vector2 length = $$anonymous$$athf.Sqrt((AB.x * AB.x) + (AB.y * AB.y));
// Vector3 example
Vector3 AB = B - A; (or A - B, for a vector pointing in the opposite direction)
Vector3 length = $$anonymous$$athf.Sqrt((AB.x * AB.x) + (AB.y * AB.y) + (AB.z * AB.z));
// Vector4 example
Vector4 AB = B - A; (or A - B, for a vector pointing in the opposite direction)
Vector4 length = $$anonymous$$athf.Sqrt((AB.x * AB.x) + (AB.y * AB.y) + (AB.z * AB.z) + (AB.w * AB.w));
That said, I hid links to each Vector format's "Distance" function up above... They do the same thing as I described above.
http://docs.unity3d.com/ScriptReference/Vector2.Distance.html
Answer by Amanna · May 18, 2016 at 10:32 AM
// http://wiki.unity3d.com/index.php/Gravity using UnityEngine; using System.Collections.Generic;
public class Gravity : MonoBehaviour {
public static float range = 1000;
void FixedUpdate ()
{
Collider[] cols = Physics.OverlapSphere(transform.position, range);
List<Rigidbody> rbs = new List<Rigidbody>();
foreach(Collider c in cols)
{
Rigidbody rb = c.attachedRigidbody;
if(rb != null && rb != rigidbody && !rbs.Contains(rb))
{
rbs.Add(rb);
Vector3 offset = transform.position - c.transform.position;
rb.AddForce( offset / offset.sqrMagnitude * rigidbody.mass);
}
}
}
}
Thanks a lot for the answer!
I just tried it out but it's still giving me that 'locking' issue, where it will go straight towards the object and just stay at the objects position, I need it to gain some speed and be pulled in that direction and keep moving past the object if it gained too much speed.
Actually I take that back, it doesn't cause the locking issue, that was due to my other script still being activated.
This is currently doing nothing for me, where and how am I supposed to use it?
Answer by jdean300 · May 19, 2016 at 09:21 AM
I'll give you some code that I wrote outside of Unity for a project a few years ago - it should give you some insight on how to accomplish this:
/// <summary>
/// Updates the velocity of all planets based on the force of gravity exerted between planets
/// </summary>
private void UpdatePlanetVelocities()
{
//foreach loop is not efficient in this case, we need to maintain knowledge about the index of a planet
for (var i = 0; i < m_planets.Count; i++)
{
for (var j = 0; j < m_planets.Count; j++)
{
//don't want to recalculate a reaction we have already visited
if (j <= i)
continue;
var force = ForceBetweenPlanets(m_planets[i], m_planets[j]);
m_planets[i].ForceThisFrame += force; //Equal and opposite forces
m_planets[j].ForceThisFrame -= force; //Equal and opposite forces
}
m_planets[i].Velocity += (m_planets[i].ForceThisFrame / (float)m_planets[i].Mass);
}
}
/// <summary>
/// Updates the position of all planets with their current velocity
/// </summary>
private void UpdatePlanetPositions()
{
foreach (var i in m_planets)
{
i.Position += i.Velocity;
}
}
/// <summary>
/// Returns the gravitional force between A & B, in the direction of A to B
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
private static Vector2f ForceBetweenPlanets(Planet a, Planet b)
{
var d = Utils.Distance(a.Position, b.Position);
//m_GravConst is just a scaling factor that affects how strong the gravity is
var forceMag = m_GravConst * (a.Mass * b.Mass) / d; //Newton's Law of Universal Gravitation
var forceVector = b.Position - a.Position;
forceVector /= (float)d; //reduce to unit vector
forceVector *= (float)forceMag; //scale to proper magnitude
return forceVector;
}
You should be able to copy most of this - just use your own list of planets that you determine based on triggers/tags, and let Unity's physics update the position of objects
Thanks a lot, I'll have a go at this tomorrow. I really appreciate the help!
Your answer
Follow this Question
Related Questions
How do I programm a Planet Gravitation? 0 Answers
2D Top Down Character being Pulled down and movement script not working? 2 Answers
Can anyone tell me what I'm doing wrong here? 1 Answer
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers