c++ - Marco Monster 的 C++ 中的 Car Physics Demo 改编,汽车行为混乱
问题描述
我正在尝试采用 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)在 C++ 中。我遇到了汽车围绕自身旋转并以不可预测的方式沿轴移动的问题(因为它对输入做出反应,但这样做是不可预测的)。在过去的 4 天里,我一直在试图找出问题所在,但一无所获。请帮忙,因为我对此感到绝望。我已将汽车的功能分成单独的类(以便更好地维护),并推断问题发生在 Wheel 类和 Car 类中。这是代码:
轮子.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();
};
轮子.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;
}
}
汽车.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;
};
汽车.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
值未在任一类中初始化,因此它具有不确定的值。唯一一次设置值是在您检查汽车是否停止时。
不可预测的运动可能是一个类似的问题。
您应该在构造函数中初始化所有类成员以避免这些问题。
为什么Wheel::SetValues
引用它的所有参数?由于只是将它们复制到内部变量中,并且它们是基本类型,因此只需将它们按值传递即可。
推荐阅读
- scikit-learn - 将最佳 GridSearch 分类器写入表中
- python - Django Redirect - 带有字符串的 URL 到带有 Slug 的 URL
- bash - 在 bash 中创建“首次运行”通知?
- javascript - Node.js:无法从同一文件中的其他函数返回值
- ios - 将 UIView 从 ViewController 移动到 Window
- java - 番石榴限速器发送更多 qps
- python - 如何在熊猫列表中查找所有元素的匹配信息
- batch-file - 运行批处理文件时系统找不到指定的路径
- c# - 是否可以在带有 .NET Core 的 Linux 上使用 Alea GPU?
- jquery - Jquery - 仅触发特定类中的模糊事件