Approximating gravity like behaviour of an asteroid

I have a large asteroid object, and I want to use physics2D to have smaller objects be attracted to it as if by gravity, and come to rest on its surface. The asteroid itself is also a dynamic physics2D object to allow it to drift around, and receive transferred momentum from impacts.

My current arrangement on the asteroid object is:

  • Smaller CircleCollider2D on surface of asteroid asset for collisions
  • RigidBody2D
  • Larger CircleCollider2D for point effector
  • PointEffector2D with negative force to attract objects

Other objects are just colliders and rigidBody2D’s

The problem is that when an object comes to rest on the surface of the asteroid, since it has not reached the actual point effector coordinates, a force is still applied to that object in the direction of the point effector ie center of the asteroid. This force in turn gets imparted on to the asteroid, and if several objects build up in a certain direction the asteroid will move in the opposite direction.

How can I approximate the behavior of a real asteroid whereby an object will impart some momentum on impact, but once they come to rest the forces reach equilibrium?

Obviously in real life the center of gravity would be slightly altered, I don’t need that level of precision. I just don’t want the asteroid zipping around.

I have tried using the collision masks / matrix. I can not find a configuration that both allows the asteroid to collide with the smaller objects, but not receive the force imparted by them after colliding.

Whenever an object is in contact with the asteroid, apply the same force that is affecting the the object also to the asteroid, but in the opposite direction. This will counteract the “gravity” force applied to the object. Both bodies should reach a stable rest state depending on the properties of the physics materials (friction, restitution).

I don’t know if you have access to the force value applied by the effector (I work on 3D physics only). If you don’t, then you could use a circle collider as a trigger, then calculate and apply the gravity force yourself when an object is in contact with the trigger. If the object is also in contact with the asteroid collider, then apply the same force value in the opposite direction to the asteroid.

Note that this is not a hack, but a physically correct behavior. It simulates the surface of the asteroid counteracting the force of the object on it.

Here’s where I landed:

private Vector2 totalForce;

private void FixedUpdate()
{
    _rigidBody.AddForce(-totalForce);
    totalForce = Vector2.zero;
   
    foreach (var rb in affectedRigidbodies)
    {
        Vector3 forceDirection = ((Vector2)transform.position - rb.position).normalized;
        float forceMagnitude = _timeNumberMgmt.hourGravForceMag * rb.mass;
        Vector2 force = forceDirection * forceMagnitude;
        rb.AddForce(force);
        totalForce += force;
    }
}

private void OnTriggerEnter2D(Collider2D other)
{
    Rigidbody2D rb = other.GetComponent<Rigidbody2D>();
    if (rb != null)
    {
        affectedRigidbodies.Add(rb);
    }
}

void OnTriggerExit2D(Collider2D other)
{
    Rigidbody2D rb = other.GetComponent<Rigidbody2D>();
    if (rb != null)
    {
        affectedRigidbodies.Remove(rb);
    }
}

Exactly as you described! I am wondering if there are ways to optimize this but the effect is as desired.

1 Like

Should the Asteroid not be Kinematic? That way forces don’t affect it. Either that or give the asteroid a crazy high relative mass so the force would still be applied but be relatively appropriate given the two masses.

I didn’t want the asteroid to be kinetic because it drifts around and reacts to particularly large impacts.

You can still do that with Kinematic. You can still move it, detect collisions and produce reactions to collisions etc. It’s up to you though; it wasn’t the only thing I suggested.

If you don’t change what the asteroid is and how it’s configured, you cannot expect it to change in how it reacts to forces.

Great! It looks good to me in terms of optimization. I’d only double-check and ensure that the OnTriggerEnter2D and OnTriggerExit2D methods work consistently in your case (i.e. the result doesn’t get altered if there are contacts with other triggers, such as in-game powerups or stuff like that).