0
\$\begingroup\$

I am currently making a game where the player constructs vehicles out of blocks. I am achieving this through having rigidbodies for each 'group of blocks' separated by 'function blocks' (e.g. motors, that can rotate) to allow for movement of the rigidbodies/groups of blocks. These function blocks connect the rigidbodies by HingeJoints.

I added gravity as the game will be set in space. I update the velocity of the vehicle in a method called on a fixed timeStep of 0.01, using AddForce.

private void UpdateVelocity()
{
    rb.AddForce(velocity - lastVelocity, ForceMode.VelocityChange)
}

The problem is, now whenever I collide with something, the vehicle freaks out and flies away at ridiculously high velocities. I've tried many different approaches but I can't figure out the solution. I don't think it's related to me using VelocityChange as it doesn't work with other ForceModes either.

I am relatively new to using joints in Unity so any help would be appreciated!

enter image description here

edit:

You should be able to reproduce with this:

GravityBody is a script attached to every object that should interact with gravity (eg. a planet, a vehicle, etc.)

public class GravityBody : MonoBehaviour
{
    public Vector3 initialVelocity;
    public Vector3 Velocity { get; private set; }
    private Vector3 lastVelocity;


    private Rigidbody rb;
    public float Mass { get; private set; }


    private void Awake()
    {
        SpaceSimulation.gravityBodies.Add(this);



        //configure rigidbody
        rb = GetComponent<Rigidbody>();
        rb.useGravity = false;
        rb.isKinematic = false;
        rb.centerOfMass = Vector3.zero;
        rb.interpolation = RigidbodyInterpolation.Interpolate;
        rb.collisionDetectionMode = CollisionDetectionMode.Discrete;


        Velocity = initialVelocity;
    }



    public void UpdateVelocity(Vector3 acceleration, float timeStep)
    {
        Velocity += acceleration * timeStep;
    }

    public void UpdatePosition()//float timeStep)
    {
        //rb.MovePosition(rb.position + Velocity * timeStep);       //doesn't hvae collision, below should achieve the same result
        rb.AddForce(Velocity - lastVelocity, ForceMode.VelocityChange);

        lastVelocity = Velocity;
    }


    public Vector3 RbPosition
    {
        get
        {
            return rb.position;
        }
    }
}

SpaceSimulation should be on only one object in the scene, it manages gravity interactions.

public class SpaceSimulation : MonoBehaviour
{
    //gravity
    public static float gravitationalConstant = 0.0001f;
    public static float timeStep = 0.01f;

    public static List<GravityBody> gravityBodies = new();



    private void Awake()
    {
        Time.fixedDeltaTime = timeStep;
    }


    private void FixedUpdate()
    {
        if (ModeManager.gameMode == GameMode.Play)
        {
            for (int i = 0; i < gravityBodies.Count; i++)
            {
                Vector3 acceleration = CalculateAcceleration(gravityBodies[i].RbPosition, gravityBodies[i]);

                gravityBodies[i].UpdateVelocity(acceleration, timeStep);
            }

            for (int i = 0; i < gravityBodies.Count; i++)
            {
                gravityBodies[i].UpdatePosition();
            }
        }
    }


    public static Vector3 CalculateAcceleration(Vector3 testBodyPos, GravityBody testBody = null)
    {
        Vector3 acceleration = Vector3.zero;

        foreach (var body in gravityBodies)
        {
            if (body != testBody && body.RbPosition != testBodyPos)
            {
                float sqrDistance = (body.RbPosition - testBodyPos).sqrMagnitude;
                Vector3 forceDirection = (body.RbPosition - testBodyPos).normalized;

                acceleration += body.Mass * timeStep * forceDirection / sqrDistance;
            }
        }

        return acceleration;
    }
\$\endgroup\$
7
  • \$\begingroup\$ What happens when one of those composite constructions collides with something else while not affected by the gravity script above? \$\endgroup\$
    – Philipp
    Oct 5 at 11:52
  • \$\begingroup\$ By the way, for forces that act constantly instead of as a one-time event, like a gravity source, you should usually use ForceMode.Acceleration. This mode automatically applies the deltaTime and should lead to better interpolation between physics frames. \$\endgroup\$
    – Philipp
    Oct 5 at 11:55
  • \$\begingroup\$ If a planet sized object collides with a small man made structure, what is your expected actual outcome? \$\endgroup\$
    – Zibelas
    Oct 5 at 12:42
  • \$\begingroup\$ You can delete the earlier partial code snippets now that you have a complete one. Do you do anything on collision to adapt the stored velocity to account for energy and momentum transfer between the objects? \$\endgroup\$
    – DMGregory
    Oct 5 at 13:12
  • \$\begingroup\$ I don't - but I assumed regular unity physics would cover that. Even still, I've tried fixed joints and they don't work either so should that not act as one body essentially? (Also it's worth noting that every group of blocks and function blocks have their own colliders) \$\endgroup\$
    – Renexx
    Oct 6 at 0:22

0

You must log in to answer this question.

Browse other questions tagged .