c++ - Marco Monster 的汽车物理演示改编为 C++,汽车行为困惑

标签 c++ c++11 game-physics game-development

我正在尝试在 C++ 中采用 Marco Monster 的物理演示(文档:http://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html 和 C 引用代码:https://github.com/spacejack/carphysics2d/blob/master/marco/Cardemo.c)。 我遇到了汽车围绕自身旋转并以不可预测的方式沿轴移动的问题(因为它对输入使用react但无法预测)。在过去的 4 天里,我一直在努力寻找问题所在,但一无所获。请帮忙,因为我对此感到绝望。我已将汽车的功能分成不同的类(以便更好地维护),并推断问题发生在 Wheel 类和 Car 类中。这是代码:


Wheel.h

class Wheel
{

public:

    Wheel(const bool &isABSOn, const float &frontAxleToCG, const float &rearAxleToCG, const float &tireGripValue, const float &lockedTireGripCoef,
        const float &lateralStiffnessFront, const float &lateralStiffnessRear, const float &brakeForceCoef, const float &ebrakeForceCoef,
        const float &brakeTorque);

    void SetValues(bool &isEbrakeOn, float &drivetrainTorque, float &steeringAngle, float &brakingInput,
        float &frontAxleLoad, float &rearAxleLoad, float &surfaceCoefficient, float &angularVelocity, Vector2f &localVelocity);

    void Update();

    Vector2f GetSumForce();
    float GetLateralTorque();


private:

    bool m_IsEBrakeOn;
    const bool m_IsABSOn;

    float m_YawSpeed, m_VehicleAngularVelocity, m_VehicleRotationAngle, m_VehicleSideSlip, m_VehicleSlipAngleFrontAxle, m_VehicleSlipAngleRearAxle,
        m_VehicleSteeringAngleRadInput,
        m_SurfaceTypeGripCoefficient, m_DrivetrainTorqueNm, m_BrakingForceInputPercentage, m_FrontAxleLoad, m_RearAxleLoad;

    const float m_CGtoFrontAxle, m_CGtoRearAxle, m_BaseTireGripValue, m_LockedTireGripCoefficent, m_LateralStiffnessFront,
        m_LateralStiffnessRear, m_BreakForceCoefficent, m_EBrakeForceCoefficent, m_BrakeTorqueLimit, m_StableSpeedBoundary;

    Vector2f m_LocalVehicleVelocity, m_VehicleLateralForceFront, m_VehicleLateralForceRear, m_VehicleLongtitudonalForceRear;

    float FrontTireGripValue();
    float RearTireGripValue();
    float CombinedBrakingForceValueRearAxle();

};

Wheel.cpp

Wheel::Wheel(const bool &isABSOn, const float &frontAxleToCG, const float &rearAxleToCG, const float &tireGripValue, const float &lockedTireGripCoef,
const float &lateralStiffnessFront, const float &lateralStiffnessRear, const float &brakeForceCoef, const float &ebrakeForceCoef,
const float &brakeTorque)
: m_IsABSOn{ isABSOn }
, m_CGtoFrontAxle{ frontAxleToCG }
, m_CGtoRearAxle{ rearAxleToCG }
, m_BaseTireGripValue{ tireGripValue }
, m_LockedTireGripCoefficent{ lockedTireGripCoef }
, m_LateralStiffnessFront { lateralStiffnessFront }
, m_LateralStiffnessRear{ lateralStiffnessRear }
, m_BreakForceCoefficent{ brakeForceCoef }
, m_EBrakeForceCoefficent{ ebrakeForceCoef }
, m_BrakeTorqueLimit{ brakeTorque }
, m_StableSpeedBoundary{ 40.f } {}

   void Wheel::Update()
{
    if ((-0.01f < m_LocalVehicleVelocity.x) || (m_LocalVehicleVelocity.x < 0.01f))
    {
        m_YawSpeed = 0.f;
    }
    else
    {
        m_YawSpeed = ((m_CGtoFrontAxle + m_CGtoRearAxle) / 2.f) * m_VehicleAngularVelocity;
    }

    if ((-0.01f < m_LocalVehicleVelocity.x) || (m_LocalVehicleVelocity.x < 0.01f))
    {
        m_VehicleRotationAngle = 0.f;
    }
    else
    {
        m_VehicleRotationAngle = std::atan2(m_YawSpeed, m_LocalVehicleVelocity.x);
    }

    if ((-0.01f < m_LocalVehicleVelocity.x) || (m_LocalVehicleVelocity.x < 0.01f))
    {
        m_VehicleSideSlip = 0.f;
    }
    else
    {
        m_VehicleSideSlip = std::atan2(m_LocalVehicleVelocity.y, m_LocalVehicleVelocity.x);
    }

    m_VehicleSlipAngleFrontAxle = m_VehicleSideSlip + m_VehicleRotationAngle - m_VehicleSteeringAngleRadInput;
    m_VehicleSlipAngleRearAxle = m_VehicleSideSlip - m_VehicleRotationAngle;

    m_VehicleLateralForceFront.x = 0.f;
    m_VehicleLateralForceFront.y = m_LateralStiffnessFront * m_VehicleSlipAngleFrontAxle;
    m_VehicleLateralForceFront.y = std::fminf(FrontTireGripValue(), m_VehicleLateralForceFront.y);
    m_VehicleLateralForceFront.y = std::fmaxf(-FrontTireGripValue(), m_VehicleLateralForceFront.y);
    m_VehicleLateralForceFront.y *= m_FrontAxleLoad;

    m_VehicleLateralForceRear.x = 0.f;
    m_VehicleLateralForceRear.y = m_LateralStiffnessRear * m_VehicleSlipAngleRearAxle;
    m_VehicleLateralForceRear.y = std::fminf(RearTireGripValue(), m_VehicleLateralForceRear.y);
    m_VehicleLateralForceRear.y = std::fmaxf(-RearTireGripValue(), m_VehicleLateralForceRear.y);
    m_VehicleLateralForceRear.y *= m_RearAxleLoad;

    m_VehicleLongtitudonalForceRear.x = m_SurfaceTypeGripCoefficient * (m_DrivetrainTorqueNm - (CombinedBrakingForceValueRearAxle() * utils::Sign(m_LocalVehicleVelocity.x)));
    m_VehicleLongtitudonalForceRear.y = 0.f;
}

Vector2f Wheel::GetSumForce()
{
    if (m_LocalVehicleVelocity.Length() < 1.0f && m_DrivetrainTorqueNm < 0.5f)
    {
        m_LocalVehicleVelocity.x = m_LocalVehicleVelocity.y = 0.f;
        m_VehicleLateralForceFront.x = m_VehicleLateralForceFront.y = m_VehicleLateralForceRear.x = m_VehicleLateralForceRear.y = 0.f;
    }

    return Vector2f
    {
        m_VehicleLongtitudonalForceRear.x + std::sinf(m_VehicleSteeringAngleRadInput) * m_VehicleLateralForceFront.x + m_VehicleLateralForceRear.x,
        m_VehicleLongtitudonalForceRear.y + std::cosf(m_VehicleSteeringAngleRadInput) * m_VehicleLateralForceFront.y + m_VehicleLateralForceRear.y
    };
}

float Wheel::GetLateralTorque()
{
    return m_CGtoFrontAxle * m_VehicleLateralForceFront.y - m_CGtoRearAxle * m_VehicleLateralForceRear.y;
}

void  Wheel::SetValues(bool &isEbrakeOn, float &drivetrainTorque, float &steeringAngle, float &brakingInput,
    float &frontAxleLoad, float &rearAxleLoad, float &surfaceCoefficient, float &angularVelocity, Vector2f &localVelocity)
{
    m_IsEBrakeOn = isEbrakeOn;
    m_DrivetrainTorqueNm = drivetrainTorque;
    m_VehicleSteeringAngleRadInput = steeringAngle;
    m_BrakingForceInputPercentage = brakingInput;
    m_FrontAxleLoad = frontAxleLoad;
    m_RearAxleLoad = rearAxleLoad;
    m_SurfaceTypeGripCoefficient = surfaceCoefficient;
    m_LocalVehicleVelocity = localVelocity;
    m_VehicleAngularVelocity = angularVelocity;
}

float Wheel::CombinedBrakingForceValueRearAxle()
{
    return (m_BrakeTorqueLimit * m_BrakingForceInputPercentage);
}

float Wheel::FrontTireGripValue()
{
    return m_BaseTireGripValue * m_SurfaceTypeGripCoefficient;
}

float Wheel::RearTireGripValue()
{
    if ((CombinedBrakingForceValueRearAxle() > m_DrivetrainTorqueNm) && (!m_IsABSOn) && (m_LocalVehicleVelocity.Length() > m_StableSpeedBoundary))
    {
        return m_BaseTireGripValue * m_LockedTireGripCoefficent * m_SurfaceTypeGripCoefficient;
    }
    else
    {
        return m_BaseTireGripValue * m_SurfaceTypeGripCoefficient;
    }
}

Car.h

class Car
{

public:

    Car(VehicleCfg *pVehicleSpecs);

    InputControl *m_pThisSteeringAndPedals;

    void Draw() const;
    void Update(float &elapsedSec);

private:

    bool m_NOSStatus, m_IsEBrakeOn;

    int m_GearShifterInput;

    float m_VehicleThrottleInpute, m_VehicleSteeringAngleRadInput, m_VehicleBrakeInput, 
        m_DrivetrainTorqueOutput, m_FrontAxleLoad, m_RearAxleLoad,
        m_ElapsedSec, m_VehicleHeadingDirectionAngleRad, m_CSHeading, m_SNHeading,
        m_VehicleRotationAngle, m_YawSpeed, m_VehicleAngularVelocity, m_VehicleSideSlip,
        m_VehicleSlipAngleFrontAxle, m_VehicleSlipAngleRearAxle,
        m_SurfaceCoefficent, m_AngularTorque, m_AngularAcceleration, m_VehicleHealthStatus;

    const float m_FrontToCG, m_RearToCG, m_CarMass, m_Inertia, m_RollingResistance, m_DragCoefficient;

    Point2f m_WorldVehicleCoordinate;

    Vector2f m_LocalVehicleVelocity, m_WorldVehicleVelocity, m_VehicleLocalAcceleration, m_VehicleWorldAcceleration,
        m_WheelForces, m_ResistanceForces, m_TotalForce;

    Suspension *m_pThisSuspension;
    Drivetrain *m_pThisDrivetrain;  
    Wheel *m_pThisWheel;
    ModularRenderer *m_pThisVehicleDrawn;

};

Car.cpp

void Car::Update(float &elapsedSec)
{
    m_ElapsedSec = elapsedSec;

    m_GearShifterInput = m_pThisSteeringAndPedals->GetCurrentGearValue();
    m_VehicleThrottleInpute = m_pThisSteeringAndPedals->GetCurrentThrottleValue(m_ElapsedSec, m_VehicleThrottleInpute);
    m_VehicleSteeringAngleRadInput = m_pThisSteeringAndPedals->GetCurrentSteeringValue(m_ElapsedSec);
    m_VehicleBrakeInput = m_pThisSteeringAndPedals->GetCurrrentBrakeValue(m_ElapsedSec);
    m_NOSStatus = m_pThisSteeringAndPedals->GetIsNOSOnValue();
    m_IsEBrakeOn = m_pThisSteeringAndPedals->GetIsEBrakeOnValue();

    m_CSHeading = std::cosf(m_VehicleHeadingDirectionAngleRad);
    m_SNHeading = std::sinf(m_VehicleHeadingDirectionAngleRad);

    m_LocalVehicleVelocity.x = m_CSHeading * m_WorldVehicleVelocity.y + m_SNHeading * m_WorldVehicleVelocity.x;
    m_LocalVehicleVelocity.y = -m_SNHeading * m_WorldVehicleVelocity.y + m_CSHeading * m_WorldVehicleVelocity.x;

    m_pThisDrivetrain->SetValues(m_NOSStatus, m_GearShifterInput, m_VehicleThrottleInpute, m_LocalVehicleVelocity.Length());
    m_DrivetrainTorqueOutput = m_pThisDrivetrain->GetDrivetrainOutput(m_ElapsedSec);

    m_pThisSuspension->SetValues(m_VehicleLocalAcceleration, m_LocalVehicleVelocity.Length());
    m_FrontAxleLoad = m_pThisSuspension->GetFrontAxleWeight();
    m_RearAxleLoad = m_pThisSuspension->GetRearAxleWeight();


    m_pThisWheel->SetValues(m_IsEBrakeOn, m_DrivetrainTorqueOutput, m_VehicleSteeringAngleRadInput, m_VehicleBrakeInput, m_FrontAxleLoad,
        m_RearAxleLoad, m_SurfaceCoefficent, m_VehicleAngularVelocity, m_LocalVehicleVelocity);
    m_pThisWheel->Update();
    m_WheelForces = m_pThisWheel->GetSumForce();
    m_AngularTorque = m_pThisWheel->GetLateralTorque();

    m_ResistanceForces.x = -((m_RollingResistance * m_LocalVehicleVelocity.x) + (m_DragCoefficient * m_LocalVehicleVelocity.x * std::abs(m_LocalVehicleVelocity.x)));
    m_ResistanceForces.y = -((m_RollingResistance * m_LocalVehicleVelocity.y) + (m_DragCoefficient * m_LocalVehicleVelocity.y * std::abs(m_LocalVehicleVelocity.y)));

    m_TotalForce.x = m_WheelForces.x + m_ResistanceForces.x;
    m_TotalForce.y = m_WheelForces.y + m_ResistanceForces.y;

    m_VehicleLocalAcceleration.x = m_TotalForce.x / m_CarMass;
    m_VehicleLocalAcceleration.y = m_TotalForce.y / m_CarMass;

    if (m_WorldVehicleVelocity.Length() < 1.0f && m_VehicleThrottleInpute < 0.5f)
    {
        m_LocalVehicleVelocity.x = m_LocalVehicleVelocity.y = 0.f;
        m_VehicleAngularVelocity = m_AngularTorque = m_AngularAcceleration = 0.f;
    }

    m_AngularAcceleration = m_AngularTorque / m_Inertia;

    m_VehicleWorldAcceleration.x = m_CSHeading * m_VehicleLocalAcceleration.y + m_SNHeading * m_VehicleLocalAcceleration.x;
    m_VehicleWorldAcceleration.y = -(m_SNHeading) * m_VehicleLocalAcceleration.y + m_CSHeading * m_VehicleLocalAcceleration.x;

    m_WorldVehicleVelocity.x += m_ElapsedSec * m_VehicleWorldAcceleration.x;
    m_WorldVehicleVelocity.y += m_ElapsedSec * m_VehicleWorldAcceleration.y;

    m_WorldVehicleCoordinate.x += m_ElapsedSec * m_WorldVehicleVelocity.x;
    m_WorldVehicleCoordinate.y += m_ElapsedSec * m_WorldVehicleVelocity.y;

    std::cout << "m_WorldVehicleCoordinate: " << m_WorldVehicleCoordinate.x << ", " << m_WorldVehicleCoordinate.y << "\n";

    m_VehicleAngularVelocity += m_ElapsedSec * m_AngularAcceleration;

    m_VehicleHeadingDirectionAngleRad += m_ElapsedSec * m_VehicleAngularVelocity;

    m_pThisVehicleDrawn->SetVariables(int(0), int(0), int(0), int(0), m_VehicleHeadingDirectionAngleRad, m_VehicleSteeringAngleRadInput, m_WorldVehicleCoordinate);

}

void Car::Draw() const
{
    m_pThisVehicleDrawn->DrawTheVehicle();
}

我认为错误是由于计算中出现的某种奇点引起的,但我看不出它发生在哪里。

最佳答案

由于汽车在旋转,我查看了您对角速度的使用。 m_VehicleAngularVelocity 值未在任何一个类中初始化,因此它具有不确定的值。唯一一次设置值是在您检查正在 parking 的汽车时。

不可预测的运动可能是一个类似的问题。

您应该在构造函数中初始化所有类成员以避免这些问题。

为什么 Wheel::SetValues 通过引用获取其所有参数?由于只是将它们复制到内部变量中,而且是基本类型,所以直接传值即可。

关于c++ - Marco Monster 的汽车物理演示改编为 C++,汽车行为困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55259230/

相关文章:

c++ - clang - shared_ptr 无法运行其删除程序

c++ - 为什么不使用 #define 来隐藏 unique_ptr 丑陋在这里工作?

python - 使用 pyglet 和 pymunk 使 Sprite 角色自然跳跃

c++ - 在 C++ 中复制多态对象

c++ - 尝试从命令行使用 g++ 编译时获取 "Access is denied"。赛格温

c++11 - 使用 emplace 添加到 std::map 时如何避免临时副本?

algorithm - 在哪里可以找到有关3D算法的信息?

math - 打砖 block 物理(射弹物理模拟)

c++ - 为什么我在使用 Aria 机器人 API 时收到 SIGSEGV 信号?

c++ - 链表中的返回遍历问题