Адаптация демонстрации физики автомобиля Marco Monster в C , автомобиль ведет себя хаотично

#c #c 11 #game-physics #game-development

#c #c 11 #игра-физика #разработка игры

Вопрос:

Я пытаюсь адаптировать демонстрацию физики Marco Monster (документ:http://www.asawicki.info/Mirror/Car Physics for Games/Car Physics for Games.html и ссылочный код C:https://github.com/spacejack/carphysics2d/blob/master/marco/Cardemo.c ) в C . Я столкнулся с проблемой, заключающейся в том, что автомобиль вращается вокруг себя и движется вдоль оси непредсказуемым образом (поскольку он реагирует на входные данные, но делает это непредсказуемо). Я потратил последние 4 дня, пытаясь найти проблему, и ничего не получил. Пожалуйста, помогите, так как я прихожу в отчаяние от этого. Я разделил функциональность автомобиля на отдельные классы (для лучшего обслуживания) и пришел к выводу, что проблема возникает в классе Wheel и в классе Car. Вот код:


Wheel.h

 class Wheel
{

public:

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

    void SetValues(bool amp;isEbrakeOn, float amp;drivetrainTorque, float amp;steeringAngle, float amp;brakingInput,
        float amp;frontAxleLoad, float amp;rearAxleLoad, float amp;surfaceCoefficient, float amp;angularVelocity, Vector2f amp;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 amp;isABSOn, const float amp;frontAxleToCG, const float amp;rearAxleToCG, const float amp;tireGripValue, const float amp;lockedTireGripCoef,
const float amp;lateralStiffnessFront, const float amp;lateralStiffnessRear, const float amp;brakeForceCoef, const float amp;ebrakeForceCoef,
const float amp;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 amp;amp; 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 amp;isEbrakeOn, float amp;drivetrainTorque, float amp;steeringAngle, float amp;brakingInput,
    float amp;frontAxleLoad, float amp;rearAxleLoad, float amp;surfaceCoefficient, float amp;angularVelocity, Vector2f amp;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) amp;amp; (!m_IsABSOn) amp;amp; (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 amp;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 amp;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 amp;amp; 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();
}
  

Я думаю, что ошибка возникает из-за какой-то особенности, возникающей в вычислениях, но я не вижу, где это происходит.

Комментарии:

1. После дальнейшего изучения проблемы, я полагаю, что это связано со способом вычисления m_VehicleLateralForceFront , m_VehicleLateralForceRear и m_AngularTorque . Хотя у меня нет точного представления о том, в чем именно проблема и, следовательно, как ее решить.

Ответ №1:

Поскольку автомобиль вращается, я посмотрел на ваше использование угловой скорости. m_VehicleAngularVelocity Значение не инициализировано ни в одном из классов, поэтому оно имеет неопределенное значение. Единственный раз, когда для него установлено значение, это в вашем чеке на остановленный автомобиль.

Непредсказуемое движение, вероятно, является аналогичной проблемой.

Вам следует инициализировать все члены вашего класса в конструкторе, чтобы избежать этих проблем.

Почему Wheel::SetValues все его параметры берутся по ссылке? Поскольку он просто копирует их во внутренние переменные, и они являются базовыми типами, просто передайте их по значению.

Комментарии:

1. Спасибо, что указали на это. Я исправил инициализацию m_VehicleAngularVelocity , но это не решило проблему полностью.