C++ 对于简单的2D',可进行提升和拖动;飞行模拟卡';

C++ 对于简单的2D',可进行提升和拖动;飞行模拟卡';,c++,simulation,box2d,game-physics,fluid-dynamics,C++,Simulation,Box2d,Game Physics,Fluid Dynamics,我正在寻找一个库或算法,可以让我在2D世界中为刚体添加简单的“飞行模拟”功能 我做了一个游戏作为一个艺术项目,虚拟鱼在水池里游泳。我开始使用Box2D/liquidfun进行基于粒子的流体模拟,当刚体在流体中拖动时,它的行为非常逼真。然而,计算量很大,即使它经过了很好的优化 相反,我想计算每个面的升力和阻力,这样物体的行为就像它们在水中移动一样,不需要粒子。这就像一些飞行模拟器的飞行模型。我相信X-Plane()就是这样工作的。 这个网站上的一些答案建议将整个“飞机”的升力和阻力建模为常数——但

我正在寻找一个库或算法,可以让我在2D世界中为刚体添加简单的“飞行模拟”功能

我做了一个游戏作为一个艺术项目,虚拟鱼在水池里游泳。我开始使用Box2D/liquidfun进行基于粒子的流体模拟,当刚体在流体中拖动时,它的行为非常逼真。然而,计算量很大,即使它经过了很好的优化

相反,我想计算每个面的升力和阻力,这样物体的行为就像它们在水中移动一样,不需要粒子。这就像一些飞行模拟器的飞行模型。我相信X-Plane()就是这样工作的。
这个网站上的一些答案建议将整个“飞机”的升力和阻力建模为常数——但它们太简单了,因为我需要展示身体几何结构的物理后果,以及它如何影响运动

我找不到一个模块提供这个功能,但我试着写我自己的。它将多边形分解为面,并对其应用升力和阻力方程。(“BoneUserData”是存储单个刚体信息的结构。Box2D/C++):

bool选择MOSTVERTEX(浮动角度,b2Vec2 p1,b2Vec2 p2){
//给定两个顶点,确定在给定方向上哪一条线最长。如果是p1,则返回true;如果是p2,则返回false。
//按方向取消顶点集的旋转,以便要测量的距离沿Y轴。
//获取质心,这是你的旋转中心
b2Vec2 thisFaceCentroid=b2Vec2((p1.x+p2.x)/2,(p1.y+p2.y)/2);
//执行旋转
b2Vec2 p1r=旋转点(thisFaceCentroid.x,thisFaceCentroid.y,角度,p1);
b2Vec2 p2r=旋转点(thisFaceCentroid.x,thisFaceCentroid.y,角度,p2);
如果(第1季度>第2季度){
返回true;
}
否则{
返回false;
}
}
//提供基于有限元分析的升力和阻力计算
void flightModel(BoneUserData*骨骼){
uint nVertices=bone->shape.GetVertexCount();
对于(uint j=0;j形状.GetVertex(j);
b2Vec2 p2=b2Vec2(0.0f,0.0f);
//使用n和n-1对创建一个面。如果n为零,则从第一个顶点到最后一个顶点创建一个面。
如果(j==0){
p2=骨骼->形状.GetVertex(nVertices-1);
}
否则{
p2=骨骼->形状。获取顶点(j-1);
}
//在考虑身体当前旋转的情况下,获取面部中心点的位置。
b2Vec2 worldCenter=骨骼->车身->GetWorldCenter();
b2Vec2 p1r=旋转点(0.0f,0.0f,bone->p_body->GetAngle(),p1);
p1r+=世界中心;
b2Vec2 p2r=rotatePoint(0.0f,0.0f,bone->p_body->GetAngle(),p2);
p2r+=世界中心;
b2Vec2 faceCenter=b2Vec2((p1r.x+p2r.x)/2,(p1r.y+p2r.y)/2);
浮动面角=atan2(p1r.y-p2r.y,p1r.x-p2r.x);
//计算迎面而来的“风”的入射角
b2Vec2 linearVelocity=bone->p_body->GetLinearVelocity();//必须获取面部中心的线速度,而不仅仅是身体本身的线速度。
//通过取半径并将其乘以角速度,可以计算面中心速度。
b2vec2localfacecenter=b2Vec2((p1.x+p2.x)/2,(p1.y+p2.y)/2);
float MaglineArveLocationFrotatingFace=(骨骼->车身->GetAngularVelocity()*幅值(localFaceCenter));//https://courses.lumenlearning.com/boundless-physics/chapter/velocity-acceleration-and-force/
b2Vec2面角速度=b2Vec2(cos(面角)*磁力线定位面,sin(面角)*磁力线定位面);
b2Vec2总速度=b2Vec2(linearVelocity.x+面角速度.x,linearVelocity.y+面角速度.y);
浮动幅度速度=幅度(总速度);
点之间的b2Vec2距离=b2Vec2(p2r.x-p1r.x,p2r.y-p1r.y);
浮动幅度面积=幅度(各点之间的距离);
向前方向的浮动角=atan2(linearVelocity.x,linearVelocity.y)-0.5*pi;
//计算阻力
浮子阻力系数=0.002;
float dragForce=magnityVelocity*magnityArea*dragCoefficient*-1;//此语句中的-1使其成为一个相反的力。
b2Vec2牵引矢量=b2Vec2(cos(正向角度)*牵引力,sin(正向角度)*牵引力*-1);
//计算升力
浮子升力系数=0.5;
浮动大气密度=1;
浮升力=升力系数*((大气密度*(振幅速度*振幅速度))/2)*振幅面积*-1;
//升力角垂直于面,但其方向取决于飞机如何迎面而来的风。
浮点数=面角+0.5*pi;
如果(选择MOSTVERTEX(方向角,p1r,p2r)){
提升力=提升力*-1;
}
b2Vec2流体动力=b2Vec2(cos(liftAngle)*liftForce,sin(liftAngle)*liftForce);
//直接在面中心向身体施加力。
bone->p_body->ApplyForce(dragVector,faceCenter,true);
if(fluidDynamicForce.x<1000和&fluidDynamicForce.y<1000
&&fluidDynamicForce.x>-1000和&fluidDynamicForce.y>-1000){
bone->p_body->ApplyForce(fluidDynamicForce,faceCenter,true);
}
}
}
然而,它受到物理错误的困扰。我知道我建模阻力的方式是不正确的,它应该取决于风的面积,而不是整个面积。但也存在其他问题,如近静止物体随机跳跃,旋转对称物体不减速,一些旋转物体
bool chooseDMostVertex(float angle, b2Vec2 p1, b2Vec2 p2) {
    // given 2 vertices, identify which one lines most in a given direction. return true if it is p1 and false if it is p2.

    // unrotate the set of vertices by the direction, so that the distance to measure is along the Y axis.
    // get the centroid, this is your rotation center
    b2Vec2 thisFaceCentroid = b2Vec2((p1.x + p2.x)/2,(p1.y+p2.y)/2);

    // perform the rotation
    b2Vec2 p1r = rotatePoint(thisFaceCentroid.x, thisFaceCentroid.y, angle, p1);
    b2Vec2 p2r = rotatePoint(thisFaceCentroid.x, thisFaceCentroid.y, angle, p2);

    if (p1r.y > p2r.y) {
        return true;
    }
    else {
        return false;
    }
}

// provides FEA-based lift and drag calculations
void flightModel(BoneUserData * bone) {

    uint nVertices = bone->shape.GetVertexCount();

    for (uint j = 0; j < nVertices; ++j)
    {
        // get the face vertices from the b2 shape
        b2Vec2 p1 = bone->shape.GetVertex(j);
        b2Vec2 p2 = b2Vec2(0.0f, 0.0f);

        // use the pair n and n-1 to make a face. if n is zero, make a face from the first to the last vertices.
        if (j == 0) {
            p2 = bone->shape.GetVertex(nVertices-1);
        }
        else {
            p2 = bone->shape.GetVertex(j-1);
        }
        
        // get the position of the face center point, taking into account the body's present rotation.
        b2Vec2 worldCenter = bone->p_body->GetWorldCenter();
        b2Vec2 p1r = rotatePoint(0.0f, 0.0f, bone->p_body->GetAngle(), p1 );
        p1r += worldCenter;
        b2Vec2 p2r = rotatePoint(0.0f, 0.0f, bone->p_body->GetAngle(), p2 );
        p2r += worldCenter;
        b2Vec2 faceCenter = b2Vec2( (p1r.x + p2r.x)/2, (p1r.y + p2r.y)/2 ) ;
        float faceAngle = atan2(p1r.y - p2r.y, p1r.x - p2r.x);

        // calculate the angle of incidence into the oncoming 'wind'
        b2Vec2 linearVelocity = bone->p_body->GetLinearVelocity();// must get the linear velocity of the face center, not just of the body itself.

        // you can calculate the face center velocity, by taking the radius and multiplying it by the angular velocity.
        b2Vec2 localFaceCenter = b2Vec2( (p1.x + p2.x)/2, (p1.y + p2.y)/2 ) ;
        float magLinearVelocityOfRotatingFace = (bone->p_body->GetAngularVelocity() * magnitude( localFaceCenter));  // https://courses.lumenlearning.com/boundless-physics/chapter/velocity-acceleration-and-force/
        b2Vec2 faceAngularVelocity = b2Vec2( cos(faceAngle) * magLinearVelocityOfRotatingFace, sin(faceAngle) * magLinearVelocityOfRotatingFace);
        b2Vec2 totalVelocity = b2Vec2(linearVelocity.x + faceAngularVelocity.x, linearVelocity.y + faceAngularVelocity.y);
        float magnitudeVelocity = magnitude(totalVelocity);

        b2Vec2 distanceBetweenPoints = b2Vec2(p2r.x - p1r.x, p2r.y - p1r.y);
        float magnitudeArea = magnitude(distanceBetweenPoints);
        float angleOfForwardDirection = atan2(linearVelocity.x, linearVelocity.y) - 0.5 * pi;

        // calculate the force of drag
        float dragCoefficient = 0.002;
        float dragForce = magnitudeVelocity * magnitudeArea * dragCoefficient * -1; // the -1 in this statement is what makes it an opposing force.
        b2Vec2 dragVector = b2Vec2( cos(angleOfForwardDirection) * dragForce , sin(angleOfForwardDirection) * dragForce *-1);

        // calculate the force of lift
        float liftCoeff  = 0.5;
        float atmosphericDensity = 1;
        float liftForce = liftCoeff * ((atmosphericDensity * (magnitudeVelocity*magnitudeVelocity))/2) * magnitudeArea * -1;

        // the lift angle is normal to the face but its direction is determined by how the plane meets the incoming wind.
        float liftAngle = faceAngle + 0.5*pi;
        if (chooseDMostVertex(angleOfForwardDirection, p1r, p2r)) {
            liftForce = liftForce * -1;
        }
        b2Vec2 fluidDynamicForce = b2Vec2(cos(liftAngle ) * liftForce, sin(liftAngle ) * liftForce );
    
        // apply the force to the body directly in the center of the face.
        bone->p_body->ApplyForce(dragVector, faceCenter, true);

        if (    fluidDynamicForce.x < 1000 && fluidDynamicForce.y < 1000
            &&  fluidDynamicForce.x > -1000 && fluidDynamicForce.y > -1000 ) {
            bone->p_body->ApplyForce(fluidDynamicForce, faceCenter, true);
        }
    }
}