2

so I'm trying to make a program that allows asteroids in a field to be attracted to each other like this: https://www.youtube.com/watch?v=iAWZwTWJmhM

I have two programs to do this, one randomly generates asteroids, the other applies gravitational force to each object. the problem is that the asteroids will get faster as they get closer until they are bullet speed and the applied forces causes them to shoot away from each other and disappear. Is there a way to make them negate their forces on contact. I tried Rigidbody.isKinematic but that makes the asteroids still instead of rotating like they would in space. ill post the code below but here are the two projects I'm using the code from. https://www.youtube.com/watch?v=Ouu3D_VHx9o https://www.youtube.com/watch?v=6rTfZ2ox2_g

Code for asteroid spawner. I added in the random scale generator.:

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

public class AsteroidFieldGenerator : MonoBehaviour
{
public Transform AsteroidPrefab;
public int fieldRadius = 50;
public int asteroidCount = 60;
public float SizeMinPercent = 1;
public float SizeMaxPercent = 100;
// Start is called before the first frame update
void Start()
{
    for (int loop = 0; loop < asteroidCount; loop++)
    {
        Instantiate(AsteroidPrefab, Random.insideUnitSphere * fieldRadius, Quaternion.identity);
        AsteroidPrefab.transform.localScale = Vector3.one * (Random.Range(SizeMinPercent, SizeMaxPercent) / 100);
    }

}

// Update is called once per frame
void Update()
{

}
}

Program for applying gravity:

'''

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

public class Attractor : MonoBehaviour
{

const float G = 667.4f;

public static List<Attractor> Attractors;

public Rigidbody rb;

void FixedUpdate()
{
    foreach (Attractor attractor in Attractors)
    {
        if (attractor != this)
            Attract(attractor);
    }
}

void OnEnable()
{
    if (Attractors == null)
        Attractors = new List<Attractor>();

    Attractors.Add(this);
}

void OnDisable()
{
    Attractors.Remove(this);
}

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

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

    if (distance == 0f)

        return;

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

    if (distance == 0)
        force = force * 0;

    rbToAttract.AddForce(force);

}

}

'''

  • You could use `OnCollisionEnter` to detect when they hit. Then determine the DOT product between the two to determine which angle they should fly off on, then apply the correct force. Don't ask me use this - http://labman.phys.utk.edu/phys221core/modules/m5/conservation_of_momentum.html – jiveturkey May 04 '20 at 17:36

1 Answers1

0

You have to apply damping (resistance) forces, similar to say atmospheri resistance (air drag). Then the total energy of the system will decrease, which make it more likely that the particles cluster together. So basically, the equations of motion should be something like

F_grv[i,j,:] = G*mj*mi * (x[j,:] - x[i,:]) / norm(x[i,:] - x[j,:])^3 
F_res[i,j,:] = - R( norm(x[i,:] - x[j,:]) ) * norm(v[i,:])^a * v[i,:] 

R(u) = non-negative function that rapidly decreases when u goes away from 0, 
       and increasing rapidly when u gets very close to 0.
a is some positive number, say 1 or 2 or more. 

dx[i,:]/dt = v[i,:]
dv[i,:]/dt = (1/mi) * sum(F_grv[i,j,:] + F_res[i,j] for j=1:n)

Here is a matlab code for the case of one particle orbiting a center of gravity with the standard Newtonian gravitational force acting on it plus a velocity dependent damping force:

function gravity_damping()
    t = 0;
    x0 = [5;1];
    x_start = [-1; 10];
    v_start = [0.15; 0.];
    x = x_start;
    v = v_start;
    h = 0.3;
    n = 700;
    k0 = 7;
    lambda = 2;
    power1 = 10;
    power2 = 2;
    hold on
    grid on
    axis([-7 8 -3 12])
    plot(x0(1), x0(2), 'ro');
    for k = 1:n
        t = t+h;
        x = x + h*v/2;
        v = v + h*F_grv(x-x0, 1, 1) + h*F_res(x-x0, v, k0, lambda, power1, power2);
        x = x + h*v/2;
        plot(x(1), x(2), 'bo');
        pause(0.1)
    end
end

function  dvdt = F_grv(x_x0, mass, gr_const)
    dvdt = - gr_const * mass * (x_x0) / norm(x_x0)^3;
end

function  dvdt = F_res(x_x0, v, k0, a, power1, power2)
    dvdt = - (k_res(norm(x_x0), k0, a, power1) * norm(v)^power2) * v;
end

function coeff = k_res(u, k0, a, power)
    coeff = k0/(1 + (a*u)^(power));
end

Futurologist
  • 1,874
  • 2
  • 7
  • 9