C# 二维球之间的吸引力

C# 二维球之间的吸引力,c#,gravity,C#,Gravity,我有一个模拟,多个圆在2D空间中移动,它们之间有弹性碰撞 我想在粒子之间加一个引力,这样粒子就可以根据质量向其他粒子移动,等等。我该怎么做呢 我的冲突管理功能如下所示: void manageCollision(Particle particleA, Particle particleB) { float distanceX = particleA.Position.X - particleB.Position.X; float distanceY = particleA.Pos

我有一个模拟,多个圆在2D空间中移动,它们之间有弹性碰撞

我想在粒子之间加一个引力,这样粒子就可以根据质量向其他粒子移动,等等。我该怎么做呢

我的冲突管理功能如下所示:

void manageCollision(Particle particleA, Particle particleB)
{
    float distanceX = particleA.Position.X - particleB.Position.X;
    float distanceY = particleA.Position.Y - particleB.Position.Y;
    double collisionAngle = Math.Atan2(distanceY, distanceX);
    double pA_magnitude = Math.Sqrt(particleA.Velocity.X * particleA.Velocity.X + particleA.Velocity.Y * particleA.Velocity.Y);
    double pB_magnitude = Math.Sqrt(particleB.Velocity.X * particleB.Velocity.X + particleB.Velocity.Y * particleB.Velocity.Y);
    double pA_direction = Math.Atan2(particleA.Velocity.Y, particleA.Velocity.X);
    double pB_direction = Math.Atan2(particleB.Velocity.Y, particleB.Velocity.X);
    double pA_newVelocityX = pA_magnitude * Math.Cos(pA_direction - collisionAngle);
    double pA_newVelocityY = pA_magnitude * Math.Sin(pA_direction - collisionAngle);
    double pB_newVelocityX = pB_magnitude * Math.Cos(pB_direction - collisionAngle);
    double pB_newVelocityY = pB_magnitude * Math.Sin(pB_direction - collisionAngle);
    double pA_finalVelocityX = ((particleA.Mass - particleB.Mass) * pA_newVelocityX + (particleB.Mass + particleB.Mass) * pB_newVelocityX) / (particleA.Mass + particleB.Mass);
    double pB_finalVelocityX = ((particleA.Mass + particleA.Mass) * pA_newVelocityX + (particleB.Mass - particleA.Mass) * pB_newVelocityX) / (particleA.Mass + particleB.Mass);
    double pA_finalVelocityY = pA_newVelocityY;
    double pB_finalVelocityY = pB_newVelocityY;
    particleA.Velocity = new Vector2((float)(Math.Cos(collisionAngle) * pA_finalVelocityX + Math.Cos(collisionAngle + Math.PI / 2) * pA_finalVelocityY), (float)(Math.Sin(collisionAngle) * pA_finalVelocityX + Math.Sin(collisionAngle + Math.PI / 2) * pA_finalVelocityY));
    particleB.Velocity = new Vector2((float)(Math.Cos(collisionAngle) * pB_finalVelocityX + Math.Cos(collisionAngle + Math.PI / 2) * pB_finalVelocityY), (float)(Math.Sin(collisionAngle) * pB_finalVelocityX + Math.Sin(collisionAngle + Math.PI / 2) * pB_finalVelocityY));
}
Vector2 globalGravity = new Vector2(0f, gravityScale / 6000);

    for (int i = 0; i < particles.Count(); i++)
{
    particles[i].Update((float)updateTimer.Interval, globalGravity);
    Vector2 position = particles[i].Position;
    Vector2 velocity = particles[i].Velocity;
    collisionWallCheck(ref position, ref velocity, particles[i].Radius);
    particles[i].Position = position;
    particles[i].Velocity = velocity;


    Particle pA = particles[i];
    for (int k = i + 1; k < particles.Count(); k++)
    {
        Particle pB = particles[k];
        Vector2 delta = pA.Position - pB.Position;
        float dist = delta.Length();

        if (dist < particles[i].Radius + particles[k].Radius && !particles[i].Colliding && !particles[k].Colliding)
        {
            particles[i].Colliding = true;
            particles[k].Colliding = true;
            manageCollision(particles[i], particles[k]);
            particles[i].initColorTable(); // Upon collision, change the color
            particles[k].initColorTable();
            totalCollisions++;
        }
        else
        {
            particles[i].Colliding = false;
            particles[k].Colliding = false;
        }
    }
}
每个球或粒子以随机质量和半径繁殖

函数在更新类型的方法中调用,如下所示:

void manageCollision(Particle particleA, Particle particleB)
{
    float distanceX = particleA.Position.X - particleB.Position.X;
    float distanceY = particleA.Position.Y - particleB.Position.Y;
    double collisionAngle = Math.Atan2(distanceY, distanceX);
    double pA_magnitude = Math.Sqrt(particleA.Velocity.X * particleA.Velocity.X + particleA.Velocity.Y * particleA.Velocity.Y);
    double pB_magnitude = Math.Sqrt(particleB.Velocity.X * particleB.Velocity.X + particleB.Velocity.Y * particleB.Velocity.Y);
    double pA_direction = Math.Atan2(particleA.Velocity.Y, particleA.Velocity.X);
    double pB_direction = Math.Atan2(particleB.Velocity.Y, particleB.Velocity.X);
    double pA_newVelocityX = pA_magnitude * Math.Cos(pA_direction - collisionAngle);
    double pA_newVelocityY = pA_magnitude * Math.Sin(pA_direction - collisionAngle);
    double pB_newVelocityX = pB_magnitude * Math.Cos(pB_direction - collisionAngle);
    double pB_newVelocityY = pB_magnitude * Math.Sin(pB_direction - collisionAngle);
    double pA_finalVelocityX = ((particleA.Mass - particleB.Mass) * pA_newVelocityX + (particleB.Mass + particleB.Mass) * pB_newVelocityX) / (particleA.Mass + particleB.Mass);
    double pB_finalVelocityX = ((particleA.Mass + particleA.Mass) * pA_newVelocityX + (particleB.Mass - particleA.Mass) * pB_newVelocityX) / (particleA.Mass + particleB.Mass);
    double pA_finalVelocityY = pA_newVelocityY;
    double pB_finalVelocityY = pB_newVelocityY;
    particleA.Velocity = new Vector2((float)(Math.Cos(collisionAngle) * pA_finalVelocityX + Math.Cos(collisionAngle + Math.PI / 2) * pA_finalVelocityY), (float)(Math.Sin(collisionAngle) * pA_finalVelocityX + Math.Sin(collisionAngle + Math.PI / 2) * pA_finalVelocityY));
    particleB.Velocity = new Vector2((float)(Math.Cos(collisionAngle) * pB_finalVelocityX + Math.Cos(collisionAngle + Math.PI / 2) * pB_finalVelocityY), (float)(Math.Sin(collisionAngle) * pB_finalVelocityX + Math.Sin(collisionAngle + Math.PI / 2) * pB_finalVelocityY));
}
Vector2 globalGravity = new Vector2(0f, gravityScale / 6000);

    for (int i = 0; i < particles.Count(); i++)
{
    particles[i].Update((float)updateTimer.Interval, globalGravity);
    Vector2 position = particles[i].Position;
    Vector2 velocity = particles[i].Velocity;
    collisionWallCheck(ref position, ref velocity, particles[i].Radius);
    particles[i].Position = position;
    particles[i].Velocity = velocity;


    Particle pA = particles[i];
    for (int k = i + 1; k < particles.Count(); k++)
    {
        Particle pB = particles[k];
        Vector2 delta = pA.Position - pB.Position;
        float dist = delta.Length();

        if (dist < particles[i].Radius + particles[k].Radius && !particles[i].Colliding && !particles[k].Colliding)
        {
            particles[i].Colliding = true;
            particles[k].Colliding = true;
            manageCollision(particles[i], particles[k]);
            particles[i].initColorTable(); // Upon collision, change the color
            particles[k].initColorTable();
            totalCollisions++;
        }
        else
        {
            particles[i].Colliding = false;
            particles[k].Colliding = false;
        }
    }
}

我现在不确定如何处理0的情况。

知道所有球的位置和它们的质量,你可以计算出任何两个物体之间感受到的力的矢量。找到从球“A”到所有其他球的向量-“A”到球“B”,“A”到“C”,“A”到“D”等。然后,简单地将所有A的向量相加,得到作用在A上的力的最终向量。重复B->A,B->C等以找到B的向量。这样做,计算新的速度,并调整步骤之间的时间量的位置。

了解所有球的位置及其质量,您可以计算任意两个物体之间的力矢量。找到从球“A”到所有其他球的向量-“A”到球“B”,“A”到“C”,“A”到“D”等。然后,简单地将所有A的向量相加,得到作用在A上的力的最终向量。重复B->A,B->C等以找到B的向量。对所有对象执行此操作,计算新的速度,并调整步骤之间的时间量的位置。

首先计算作用在每个对象上的重力。这是由

F = Gm1m2/r*r
其中m1和m2是两个物体的质量,G是,r是两个物体之间的距离

现在,r是一个向量,所以你可能想把它分成单独的部分——Fx和Fy。您可以按如下方式执行此操作:

Fx = F * cos(theta)
Fy = F * sin(theta)
对于每个质量,计算作用于它和其他每个物体上的重力。得到重力的净力。(请注意,该链接符合您的兴趣,但需要很长时间才能切中要害)。在这一点上,每个物体上都有一个净力,从中可以计算加速度。以下是达到这一点的代码:

const double G = 6.67398 * 0.00000000001;

for (int i = 0; i < particles.Count(); i++)
{
    double sumX = 0;
    double sumY = 0;

    for (int j = 0; j < particles.Count(); j++)
    {
        // Don't add attraction to self
        if (i == j)
            continue;

        double distanceX = particles[i].Position.X - particles[j].Position.X;
        double distanceY = particles[i].Position.Y - particles[j].Position.Y;
        double r = Math.Sqrt(Math.Pow(distanceX, 2) + Math.Pow(distanceY, 2));
        double force = G * particles[i].Mass * particles[j].Mass / (r * r);
        double theta = Math.Tan(distanceY / distanceX);
        sumX += force * Math.Cos(theta);
        sumY += force * Math.Sin(theta);
    }

    double netForce = Math.Sqrt(Math.Pow(sumX, 2) + Math.Pow(sumY, 2));
    double a = netForce / particles[i].Mass;
    double aTheta = Math.Tan(sumY / sumX);

    // Here we get accelerations for X and Y.  You can probably figure out velocities from here.
    double aX = a * Math.Cos(aTheta);
    double aY = a * Math.Sin(aTheta);
}
constdouble G=6.67398*0.00000000001;
对于(int i=0;i
注释

这并没有考虑到0值之类的东西——您必须清理此代码以处理特殊情况,然后才能运行而不会崩溃

在计算所有力之前,不要更新任何位置,否则将禁用列表中的后续元素

另一件值得注意的事情是:这个算法是O(n^2),所以如果你有多个实体,它将需要大量的压缩。不幸的是,事情就是这样;如果你找到一种快速计算大量天体引力的方法,你可能应该打电话给NASA


根据您的坐标系,您可能会发现y向量正在反转。这是因为欧几里德几何学认为y的正值是“向上”的,而程序员倾向于从屏幕顶部“向下”以正单位测量y。这会破坏你的角度和物体。

首先计算作用在每个物体上的重力。这是由

F = Gm1m2/r*r
其中m1和m2是两个物体的质量,G是,r是两个物体之间的距离

现在,r是一个向量,所以你可能想把它分成单独的部分——Fx和Fy。您可以按如下方式执行此操作:

Fx = F * cos(theta)
Fy = F * sin(theta)
对于每个质量,计算作用于它和其他每个物体上的重力。得到重力的净力。(请注意,该链接符合您的兴趣,但需要很长时间才能切中要害)。在这一点上,每个物体上都有一个净力,从中可以计算加速度。以下是达到这一点的代码:

const double G = 6.67398 * 0.00000000001;

for (int i = 0; i < particles.Count(); i++)
{
    double sumX = 0;
    double sumY = 0;

    for (int j = 0; j < particles.Count(); j++)
    {
        // Don't add attraction to self
        if (i == j)
            continue;

        double distanceX = particles[i].Position.X - particles[j].Position.X;
        double distanceY = particles[i].Position.Y - particles[j].Position.Y;
        double r = Math.Sqrt(Math.Pow(distanceX, 2) + Math.Pow(distanceY, 2));
        double force = G * particles[i].Mass * particles[j].Mass / (r * r);
        double theta = Math.Tan(distanceY / distanceX);
        sumX += force * Math.Cos(theta);
        sumY += force * Math.Sin(theta);
    }

    double netForce = Math.Sqrt(Math.Pow(sumX, 2) + Math.Pow(sumY, 2));
    double a = netForce / particles[i].Mass;
    double aTheta = Math.Tan(sumY / sumX);

    // Here we get accelerations for X and Y.  You can probably figure out velocities from here.
    double aX = a * Math.Cos(aTheta);
    double aY = a * Math.Sin(aTheta);
}
constdouble G=6.67398*0.00000000001;
对于(int i=0;i
注释

这不需要像0-va这样的东西