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;
        }
    }
}

我存储每个球的初始位置,速度和质量。

我显然需要做的,不知道如何实现的是:

  • 计算引力的大小和方向。
  • 知道了力量,你可以计算出每个人的加速度。
  • 知道加速度可以计算出新的速度。
  • 知道速度可以计算出新的位置。
  • 我基本上对这个方程式摇摆不定,我想通过在两个球之间建立吸引力开始。

    使用Steven的建议,这是新的集成代码。

    void updateTimer_Tick(object sender, EventArgs e)
    {
        const double G = 6.67398 * 0.00000000001;
    
        for (int i = 0; i < particles.Count(); i++)
        {
            double sumX = 0;
            double sumY = 0;
    
            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();
                    particles[k].initColorTable();
                    totalCollisions++;
                    particles[i].Colliding = false;
                    particles[k].Colliding = false;
                }
                else
                {
                    double distanceX = particles[i].Position.X - particles[k].Position.X;
                    double distanceY = particles[i].Position.Y - particles[k].Position.Y;
                    double r = Math.Sqrt(Math.Pow(distanceX, 2) + Math.Pow(distanceY, 2));
                    double force = G * particles[i].Mass * particles[k].Mass / (r * r);
                    double theta = Math.Tan(distanceY / distanceX);
                    sumX += force * Math.Cos(theta);
                    sumY += force * Math.Sin(theta);
                    particles[i].Colliding = false;
                    particles[k].Colliding = false;
                }
            }
            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);
            Vector2 accel = new Vector2((float)aX, (float)aY);
    
            particles[i].Update((float)updateTimer.Interval, accel);
            //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 + accel;
        }
        Draw();
    }
    

    粒子的更新函数很简单,并且在它使用全局重力矢量之前是0,0。

            public void Update(float timeStep, Vector2 gravity)
            {
                velocity = velocity + timeStep * gravity;
                position = position + timeStep * velocity;
            }
    

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


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

    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);
    }
    

    笔记

    这不会将0值等东西考虑在内 - 您必须清理此代码以处理特殊情况,然后才能运行而不会崩溃。

    在计算完所有力量之前,不要更新任何位置,否则将在列表中稍后的元素处于关闭状态。

    另一件值得注意的事情是:这个算法是O(n ^ 2),所以如果你有更多的物体,它会花费很多的时间。 不幸的是,这只是它的方式; 如果你找到一个快速计算大量物体的引力的方法,你应该叫NASA。

    根据你的坐标系,你可能会发现y向量被颠倒过来。 这是因为欧几里德几何认为y的正值是“向上”,而程序员倾向于从屏幕的顶部向下“正向下”测量y。 这会对你的角度和事物造成破坏。


    知道所有的球和它们的质量的位置,你可以计算任何两个物体之间感觉到的力的矢量。 从A球到所有其他球找到向量 - 'A'将球'B','A'到'C','A'到'D'等。然后,简单地将A的所有矢量添加到得到一个作用于A的力的最终矢量。对于B→A,B→C等重复以找到B的矢量。 为此做所有这些,计算新的速度,并根据步骤之间的时间量来调整位置。

    链接地址: http://www.djcxy.com/p/65399.html

    上一篇: Attraction Force between 2D balls

    下一篇: Android set the gravity for a TextView programmatically