One way collisions with rigidbodies

This is gonna be a little bit complicated but bare with me. Basically i have a game with a mini solar system that uses gravity physics with rigidbodied using newtons equations. There are also smaller objects (like the player or crates) where a surface gravity is applied. I have a little ui tool that essentially shows me how the planets will go based on the mass and initial velocity9201852--1283523--upload_2023-8-8_2-4-25.png

but i realized it deviated off of this path and the planets would crash into each other. I ran it twice just watching the planets move, once like normal, where they crashed into each other, and one where i disabled everything except the planets themselves, and when i did that it followed the path perfectly

I also realized that if there were a lot of stationary objects on one side then the planet would be pushed in the opposite direction.

I know what the problem is but dont know how to fix it. Basically the gravity is being applied to all the objects continuously which then also applies the extra force on the planet itself. I tried using the layer collision matrix but i dont think it works that way.

Basically i need a way to make it so that the individual objects collide with the planets like normally, but the planets arent affected by these objects so that they stay on their paths and continue their orbits

Does anyone know how this is possible?

No, nothing on a computer is continuous. It’s a discrete simulation and as such it will accumulate error over time.

Orbital mechanics are particularly problematic for this as the more you go around, the more the error term becomes, and the more that feeds back into the distance calculation for the attractive force, leading to more error and degenerate orbits.

Stable orbits are best accomplished parametrically: express each planet’s position in terms of a global time value. See below.

Beyond that, to get physics working, you must use it correctly.

With Physics (or Physics2D), never manipulate the Transform directly. If you manipulate the Transform directly, you are bypassing the physics system and you can reasonably expect glitching and missed collisions and other physics mayhem.

This means you may not change transform.position, transform.rotation, you may not call transform.Translate(), transform.Rotate() or other such methods, and also transform.localScale is off limits. You also cannot set rigidbody.position or rigidbody.rotation directly. These ALL bypass physics.

Always use the .MovePosition() and .MoveRotation() methods on the Rigidbody (or Rigidbody2D) instance in order to move or rotate things. Doing this keeps the physics system informed about what is going on.

https://discussions.unity.com/t/866410/5

https://discussions.unity.com/t/878046/8

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// @kurtdekker
// - simple demo parametric circular orbits
// - put this on a visible GameObject and watch it orbit!

public class PlanetaryOrbits : MonoBehaviour
{
    [Header( "Degrees per second.")]
    public float Rate = 50;

    [Header( "Degrees offset at t == 0")]
    public float Phase = 0;

    [Header( "Orbital radius.")]
    public float Radius = 3.0f;

    [Header( "Orbital center.")]
    public Vector3 Center;

    float age;

    void Update ()
    {
        age += Time.deltaTime;

        float angle = Phase + Rate * age;

        Vector3 position = Vector3.right;

        // scale out to radius
        position *= Radius;

        // rotate around the +Z axis
        position = Quaternion.Euler( 0, 0, angle) * position;

        // offset to center
        position += Center;

        // assign!
        transform.position = position;
    }
}

Thank you for your reply, however, that is not what im doing at all and i have no idea where you got that as that would completely defeat the purpose. It uses physics and their own gravities to move, somewhat like real life
void

FixedUpdate()
    {
        if (Application.isPlaying)
        {

            foreach (CelestialBody attractor in CelestialBodies)
            {
                if (attractor != this)
                    Attract(attractor);
            }
            foreach (GravityObject rb in GravityObject.gravityObjects)
            {
                AttractOBJ(rb.rb);
            }
        }
    }

    void Attract(CelestialBody objToAttract)
    {
        Rigidbody rbToAttract = objToAttract.rb;

        Vector3 direction = rb.position - rbToAttract.position;
        float distance = direction.sqrMagnitude;

        if (distance == 0f)
            return;

        float forceMagnitude = G * (rb.mass * rbToAttract.mass) / distance; // Mathf.Pow(distance, 2);
        Vector3 force = direction.normalized * forceMagnitude;

        rbToAttract.AddForce(force);
    }

    void AttractOBJ(Rigidbody objToAttract)
    {
        Rigidbody rbToAttract = objToAttract.GetComponent<Rigidbody>();

        float distance = Vector3.Distance(transform.position, objToAttract.transform.position);

        if (distance > raiuds * 5f)
            return;

        Vector3 targetDir = (objToAttract.transform.position - transform.position).normalized;
        Vector3 bodyUp = objToAttract.transform.up;
        if (rbToAttract.transform.tag == "Player" || rbToAttract.transform.tag == "Animal")
        {
             objToAttract.transform.rotation = Quaternion.FromToRotation(bodyUp, targetDir) * objToAttract.transform.rotation;

        };
        rbToAttract.AddForce(targetDir * -surfaceGravity);

    }

This is how i handle the movement of planets and stuff, and because they attract each other i dont have to use transform.Translate(), transform.Rotate() in the first place like you assumed i was, instead i give them an inital velocity and they orbit each other naturally

Again, this is ALL THE CODE being used to move the planets

    void Attract(CelestialBody objToAttract)
    {
        Rigidbody rbToAttract = objToAttract.rb;

        Vector3 direction = rb.position - rbToAttract.position;
        float distance = direction.sqrMagnitude;

        if (distance == 0f)
            return;

        float forceMagnitude = G * (rb.mass * rbToAttract.mass) / distance; // Mathf.Pow(distance, 2);
        Vector3 force = direction.normalized * forceMagnitude;

        rbToAttract.AddForce(force);
    }

Which does not use transform.Translate() OR transform.Rotate()

Like i stated previously, i believe the problem arises with all the extra objects being pulled by the surface gravity (the ‘AttractOBJ’ method)

Which looks like this

  void AttractOBJ(Rigidbody objToAttract)
    {
        Rigidbody rbToAttract = objToAttract.GetComponent<Rigidbody>();

        float distance = Vector3.Distance(transform.position, objToAttract.transform.position);

        if (distance > raiuds * 5f)
            return;

        Vector3 targetDir = (objToAttract.transform.position - transform.position).normalized;
        Vector3 bodyUp = objToAttract.transform.up;
        if (rbToAttract.transform.tag == "Player" || rbToAttract.transform.tag == "Animal")
        {
             objToAttract.transform.rotation = Quaternion.FromToRotation(bodyUp, targetDir) * objToAttract.transform.rotation;

        }
        rbToAttract.AddForce(targetDir * -surfaceGravity);

    }

Like i said before i think that while these objects are on the ground gravity is still being applied to them which causes them to exert some of that force back onto the planet theyre on. I believe this because i have one much less complicated planet that is water (no solid floor) with a landing pad on the side with a few crates and it would always deviate in that direction. I drew a diagram to help with this concept


9202914--1283727--upload_2023-8-8_9-34-44.jpeg
I tried making it so the velocity would be saved and reloaded after so the gravity didnt have any effect but that didnt work

        Vector3 oldVelocity = rb.velocity;
        rbToAttract.AddForce(targetDir * -surfaceGravity);
        rb.velocity = oldVelocity;

I realize i wasnt very clear in my first place in what exactly the problem was but i hope this makes it clearer.
Any further help is appreciated