C++ & SFML中的移动球与非移动球的碰撞

zdwk9cvp  于 2023-08-09  发布在  其他
关注(0)|答案(2)|浏览(123)

所以,基本上我正在尝试使用SFML在C++中实现基本重力模拟器,这是可行的,但我遇到了碰撞问题。有一个行星(引力源)-不可移动的球,它没有任何速度,不改变它的位置,它是固定的,我们有粒子-可移动的球对引力源作出React。在某个时刻,这两个球将碰撞,我试图计算正确的新的速度矢量-碰撞后,为粒子(重力源不移动!),但无论我做什么,这都不是我想达到的目标。
感谢所有这将是善良的帮助我解决这个问题!
以下是我目前为止创建的方法:

void updatePhysics(GravitySource& gravitySource, float deltaTime)
    {
        //Normal Vector
        float distanceX = gravitySource.getPos().x - pos.x;
        float distanceY = gravitySource.getPos().y - pos.y;

        //Distance between GravitySource and Particle
        float distance = std::sqrt(distanceX * distanceX + distanceY * distanceY);

        //Simplifying division to speed up calculations
        float inverseDistance = 1.f / distance;

        //Unit Vector
        float normalizedX = inverseDistance * distanceX;
        float normalizedY = inverseDistance * distanceY;

        float inverseSquareDropOff = inverseDistance * inverseDistance;

        //Calculating Acceleration
        float accelerationX = normalizedX * gravitySource.getStrength() * inverseSquareDropOff * deltaTime;
        float accelerationY = normalizedY * gravitySource.getStrength() * inverseSquareDropOff * deltaTime;

        //Updating Velocity
        vel.x += accelerationX;
        vel.y += accelerationY;

        //Updating Position
        pos.x += vel.x;
        pos.y += vel.y;

        //Updating Render Position
        relPos.x = pos.x - radius;
        relPos.y = pos.y - radius;

        //TODO: Make collision work properly!!!
        //Checking for collision
        if (distance <= radius + gravitySource.getRadius())
        {
            //Tangent Vector
            float tangentX = -normalizedY;
            float tangentY = normalizedX;

            //Velocity scalar in normal direction
            float normalScalarX = normalizedX * vel.x;
            float normalScalarY = normalizedY * vel.y;

            //New Unit Vector
            normalizedX = normalScalarX * normalizedX;
            normalizedY = normalScalarY * normalizedY;

            std::cout << vel.x << " " << vel.y << std::endl;
            vel.x = normalizedX + tangentX;
            vel.y = normalizedY + tangentY;
            std::cout << vel.x << " " << vel.y << std::endl;
        }
    }
class GravitySource
{
    sf::Vector2f pos;
    sf::Vector2f relPos;
    float strength;
    float radius;
    sf::CircleShape circleShape;
};
class Particle
{
    sf::Vector2f pos;
    sf::Vector2f relPos;
    sf::Vector2f vel;
    float radius;
    sf::CircleShape circleShape;
};
odopli94

odopli941#

Lennard-Jones势是应用平滑推+拉交互的简单方法:
x1c 0d1x的数据

struct Particle
    {
        float x, y, vx, vy;
        bool movable;
        float fx, fy;
        Particle(float xP, float yP, float vxP, float vyP, bool mP)
        {
            x = xP;
            y = yP;
            vx = vxP;
            vy = vyP;
            movable = mP;
            fx = 0;
            fy = 0;
        }

        void ResetForce() { fx = 0; fy = 0; }

        void InteractionForce(Particle & p)
        {
            float dx = x - p.x;
            float dy = y - p.y;
            float r = std::sqrt(dx * dx + dy * dy);
            float gravitationPuller = r * r * r;
            float gravitationPusher = r * r * r * r;
            float fx0 = dx / gravitationPuller;
            float fy0 = dy / gravitationPuller;
            float fx1 = 100.0f*dx / gravitationPusher;
            float fy1 = 100.0f * dy / gravitationPusher;
            p.fx += fx0 - fx1;
            p.fy += fy0 - fy1;
            fx -= fx0 - fx1;
            fy -= fy0 - fy1;
        }

        void MoveEuler(float dt)
        {
            if (movable)
            {
                x += vx * dt;
                y += vy * dt;
                vx += fx * dt;
                vy += fy * dt;
            }
        }

    };

    cv::namedWindow("test");
    cv::Mat img0(800, 600, CV_32FC3);
    img0 = 0;
    std::vector<Particle> particles;
    for (int i = 0; i < 10; i++)
    {
        particles.emplace_back((i % 3)*100 + i*40, (i / 3)*100, 0, 0, i != 0);
    }

    for (int i = 0; i < 10000; i++)
    {
        cv::Mat img = img0.clone();
        for (int j = 0; j < particles.size(); j++)
            particles[j].ResetForce();

        for (int j = 0; j < particles.size()-1; j++)
        {
            for (int k = j + 1; k < particles.size(); k++)
            {
                particles[j].InteractionForce(particles[k]);
            }
        }

        for (int j = 0; j < particles.size(); j++)
            particles[j].MoveEuler(5.0f);

        for (int j = 0; j < particles.size(); j++)
        {
            if(particles[j].movable)
                cv::circle(img, cv::Point2f(particles[j].x, particles[j].y), 20, cv::Scalar(50, 100, 150),cv::FILLED);
            else
                cv::circle(img, cv::Point2f(particles[j].x, particles[j].y), 30, cv::Scalar(250, 100, 150), cv::FILLED);
        }

        cv::imshow("test", img.clone());
        cv::waitKey(1);
    }

字符串

lskq00tm

lskq00tm2#

所以我终于在@n.m.couldbeanAI的帮助下弄明白了,代码看起来像这样(这个函数的其余部分你已经在问题中了):

//Checking for collision
    if (distance <= radius + gravitySource.getRadius())
    {
        //Projection Vector
        float projectionX = (vel.x * normalizedX + vel.y * normalizedY) * normalizedX;
        float projectionY = (vel.x * normalizedX + vel.y * normalizedY) * normalizedY;

        //Calculating new Velocity Vector
        vel.x = vel.x - 2 * projectionX;
        vel.y = vel.y - 2 * projectionY;
    }

字符串
谢谢大家的帮助!

相关问题