Skip to content

Commit

Permalink
📜 example_game_engineDiag.as: added 'calc' tab.
Browse files Browse the repository at this point in the history
  • Loading branch information
ohlidalp committed Sep 12, 2024
1 parent ac73d47 commit f20db9e
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 65 deletions.
212 changes: 160 additions & 52 deletions resources/scripts/example_game_engineDiag.as
Original file line number Diff line number Diff line change
@@ -1,14 +1,53 @@
/// \title Engine diag script
/// \title Engine + Clutch diag script
/// \brief Shows config params and state of engine simulation



// #region FrameStep

vector2 cfgPlotSize(0.f, 45.f); // 0=autoresize
bool cfgUseGlobalGearForThresholdCalc = false; // by default 1st gear is used, which may be a bug.

// assume 60FPS = circa 3 sec
const int MAX_SAMPLES = 3*60;
array<float> clutchBuf(MAX_SAMPLES, 0.f);
array<float> rpmBuf(MAX_SAMPLES, 0.f);
array<float> clutchTorqueBuf(MAX_SAMPLES, 0.f);
array<float> calcGearboxSpinnerBuf(MAX_SAMPLES, 0.f);
array<float> calcClutchTorqueBuf(MAX_SAMPLES, 0.f);
array<float> calcForceThresholdBuf(MAX_SAMPLES, 0.f);
array<float> calcClutchTorqueClampedBuf(MAX_SAMPLES, 0.f);
array<float> calcClutchTorqueFinalBuf(MAX_SAMPLES, 0.f);

void updateFloatBuf(array<float>@ buf, float f)
{
buf.removeAt(0);
buf.insertLast(f);
}

void updateEnginePlotBuffers(EngineSimClass@ engine)
{
// Engine state values
updateFloatBuf(clutchBuf, engine.getClutch());
updateFloatBuf(rpmBuf, engine.getRPM());
updateFloatBuf(clutchTorqueBuf, engine.getTorque());

// Replicating the clutch torque calculation
float gearboxspinner = engine.getRPM() / engine.getGearRatio(engine.getGear());
updateFloatBuf(calcGearboxSpinnerBuf, gearboxspinner);

float clutchTorque = (gearboxspinner - engine.getWheelSpin()) * engine.getClutch() * engine.getClutchForce();
updateFloatBuf(calcClutchTorqueBuf, clutchTorque);

float forceThreshold = 1.5f * fmax(engine.getTorque(), engine.getEnginePower()) * fabs(engine.getGearRatio(cfgUseGlobalGearForThresholdCalc ? 0 : 1)); // gear 1=BUG? should probably be 0=global
updateFloatBuf(calcForceThresholdBuf, forceThreshold);

float clutchTorqueClamped = fclamp(clutchTorque, -forceThreshold, forceThreshold);
updateFloatBuf(calcClutchTorqueClampedBuf, clutchTorqueClamped);

float clutchTorqueFinal = clutchTorqueClamped * (1.f - fexp(-fabs(gearboxspinner - engine.getWheelSpin())));
updateFloatBuf(calcClutchTorqueFinalBuf, clutchTorqueFinal);
}

void frameStep(float dt)
{
Expand All @@ -28,8 +67,8 @@ void frameStep(float dt)
}
else
{
clutchBuf.removeAt(0); clutchBuf.insertLast(engine.getClutch());
rpmBuf.removeAt(0); rpmBuf.insertLast(engine.getRPM());
updateEnginePlotBuffers(engine);

drawEngineDiagUI(engine);
}
}
Expand All @@ -39,17 +78,48 @@ void frameStep(float dt)
// #endregion

// #region UI drawing
void drawTableRow(string key, float val)
{
ImGui::TextDisabled(key); ImGui::NextColumn(); ImGui::Text(formatFloat(val, "", 0, 3)); ImGui::NextColumn();
}

void drawTableRow(string key, int val)
{
ImGui::TextDisabled(key); ImGui::NextColumn(); ImGui::Text(''+val); ImGui::NextColumn();
}

void drawTableRow(string key, bool val)
{
ImGui::TextDisabled(key); ImGui::NextColumn(); ImGui::Text(val ? 'true' : 'false'); ImGui::NextColumn();
}

void drawTableRowPlot(string key, array<float>@ buf, float rangeMin, float rangeMax)
{
ImGui::TextDisabled(key);
ImGui::NextColumn();
plotFloatBuf(buf, rangeMin, rangeMax);
ImGui::NextColumn();
}

void plotFloatBuf(array<float>@ buf, float rangeMin, float rangeMax)
{
//DOC: "void PlotLines(const string&in label, array<float>&in values, int values_count, int values_offset = 0, const string&in overlay_text = string(), float scale_min = FLT_MAX, float scale_max = FLT_MAX, vector2 graph_size = vector2(0,0))",
ImGui::PlotLines("", buf, MAX_SAMPLES, 0, "", rangeMin, rangeMax, cfgPlotSize);
ImGui::SameLine();
float val = buf[buf.length()-1];
ImGui::Text(formatFloat(val, "", 0, 3));
}

void drawEngineDiagUI(EngineSimClass@ engine)
{
if ( ImGui::CollapsingHeader('engine args'))
if (ImGui::CollapsingHeader('engine args'))
{
ImGui::Columns(2);

ImGui::TextDisabled("min RPM"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getMinRPM(), "", 0, 3));ImGui::NextColumn(); //float getMinRPM() const
ImGui::TextDisabled("max RPM"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getMaxRPM(), "", 0, 3));ImGui::NextColumn(); //float getMaxRPM() const
ImGui::TextDisabled("torque"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getEngineTorque(), "", 0, 3));ImGui::NextColumn(); //float getEngineTorque() const
ImGui::TextDisabled("diff ratio"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getDiffRatio(), "", 0, 3));ImGui::NextColumn(); //float getDiffRatio() const

drawTableRow("getMinRPM", engine.getMinRPM());
drawTableRow("getMaxRPM", engine.getMaxRPM());
drawTableRow("getEngineTorque", engine.getEngineTorque());
drawTableRow("getDiffRatio", engine.getDiffRatio());

ImGui::Columns(1);

Expand All @@ -67,61 +137,99 @@ void drawEngineDiagUI(EngineSimClass@ engine)
}


if ( ImGui::CollapsingHeader("engoption args"))
if (ImGui::CollapsingHeader("engoption args"))
{
ImGui::Columns(2);

ImGui::TextDisabled("inertia"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getEngineInertia(), "", 0, 3)); //float getEngineInertia()
ImGui::TextDisabled("type"); ImGui::NextColumn(); ImGui::Text(''+engine.getEngineType());ImGui::NextColumn(); //uint8 getEngineType()
ImGui::TextDisabled("is electric"); ImGui::NextColumn(); ImGui::Text(''+engine.isElectric());ImGui::NextColumn(); //bool isElectric()
ImGui::TextDisabled("has air"); ImGui::NextColumn(); ImGui::Text(''+engine.hasAir());ImGui::NextColumn(); //bool hasAir()
ImGui::TextDisabled("has turbo"); ImGui::NextColumn(); ImGui::Text(''+engine.hasTurbo());ImGui::NextColumn(); //bool hasTurbo()
ImGui::TextDisabled("clutch force"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getClutchForce(), "", 0, 3));ImGui::NextColumn(); //float getClutchForce()
ImGui::TextDisabled("shift time"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getShiftTime(), "", 0, 3));ImGui::NextColumn(); //float getShiftTime()
ImGui::TextDisabled("clutch time"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getClutchTime(), "", 0, 3));ImGui::NextColumn();//float getClutchTime()
ImGui::TextDisabled("post shift time"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getPostShiftTime(), "", 0, 3));ImGui::NextColumn();//float getPostShiftTime()
ImGui::TextDisabled("stall RPM"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getStallRPM(), "", 0, 3));ImGui::NextColumn();//float getStallRPM() const
ImGui::TextDisabled("idle RPM"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getIdleRPM(), "", 0, 3));ImGui::NextColumn();//float getIdleRPM() const
ImGui::TextDisabled("max idle mixture"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getMaxIdleMixture(), "", 0, 3));ImGui::NextColumn();//float getMaxIdleMixture()
ImGui::TextDisabled("min idle mixture"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getMinIdleMixture(), "", 0, 3));ImGui::NextColumn();//float getMinIdleMixture()
ImGui::TextDisabled("braking torque"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getBrakingTorque(), "", 0, 3));ImGui::NextColumn();//float getBrakingTorque()
drawTableRow("getEngineInertia", engine.getEngineInertia());
drawTableRow("getEngineType", engine.getEngineType()); //uint8
drawTableRow("isElectric", engine.isElectric()); // bool
drawTableRow("hasAir", engine.hasAir()); // bool
drawTableRow("hasTurbo", engine.hasTurbo()); // bool
drawTableRow("getClutchForce", engine.getClutchForce());
drawTableRow("getShiftTime", engine.getShiftTime());
drawTableRow("getClutchTime", engine.getClutchTime());
drawTableRow("getPostShiftTime", engine.getPostShiftTime());
drawTableRow("getStallRPM", engine.getStallRPM());
drawTableRow("getIdleRPM", engine.getIdleRPM());
drawTableRow("getMaxIdleMixture", engine.getMaxIdleMixture());
drawTableRow("getMinIdleMixture", engine.getMinIdleMixture());
drawTableRow("getBrakingTorque", engine.getBrakingTorque());

ImGui::Columns(1);
}

if (ImGui::CollapsingHeader('state'))
{
ImGui::Columns(2);
ImGui::TextDisabled("acc"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getAcc(), "", 0, 3)); ImGui::NextColumn(); //float

//DOC: "void PlotLines(const string&in label, array<float>&in values, int values_count, int values_offset = 0, const string&in overlay_text = string(), float scale_min = FLT_MAX, float scale_max = FLT_MAX, vector2 graph_size = vector2(0,0))",
ImGui::TextDisabled("clutch (0.0 - 1.0)"); ImGui::NextColumn();
ImGui::PlotLines("", clutchBuf, MAX_SAMPLES, 0, "", 0.f, 1.f); ImGui::SameLine();
ImGui::Text(formatFloat(engine.getClutch(), "", 0, 3)); ImGui::NextColumn(); //float
drawTableRow("getAcc", engine.getAcc());
drawTableRowPlot("getClutch (0.0 - 1.0)", clutchBuf, 0.f, 1.f);
drawTableRow("getCrankFactor", engine.getCrankFactor());
drawTableRowPlot("getRPM (min - max)", rpmBuf, engine.getMinRPM(), engine.getMaxRPM());
drawTableRow("getSmoke", engine.getSmoke());
drawTableRowPlot("getTorque (0 - clutchforce)", clutchTorqueBuf, 0.f, engine.getClutchForce());
drawTableRow("getTurboPSI", engine.getTurboPSI());
drawTableRow("getAutoMode", engine.getAutoMode());//SimGearboxMode
drawTableRow("getGear", engine.getGear());
drawTableRow("getGearRange", engine.getGearRange());
drawTableRow("isRunning", engine.isRunning()); // bool
drawTableRow("hasContact", engine.hasContact()); //bool
drawTableRow("getAutoShift", engine.getAutoShift()); //autoswitch
drawTableRow("getCurEngineTorque", engine.getCurEngineTorque());
drawTableRow("getInputShaftRPM", engine.getInputShaftRPM());
drawTableRow("getDriveRatio", engine.getDriveRatio());
drawTableRow("getEnginePower", engine.getEnginePower());
drawTableRow("getTurboPower", engine.getTurboPower());
drawTableRow("getIdleMixture", engine.getIdleMixture());
drawTableRow("getPrimeMixture", engine.getPrimeMixture());
drawTableRow("getAccToHoldRPM", engine.getAccToHoldRPM());

ImGui::Columns(1);
}

if (ImGui::CollapsingHeader("calc"))
{
ImGui::TextDisabled('// Replicating the clutch torque calculation');
ImGui::SameLine();
ImGui::Checkbox("cfgUseGlobalGearForThresholdCalc (visual only)", cfgUseGlobalGearForThresholdCalc);
ImGui::Separator();

ImGui::TextDisabled('float gearboxspinner = engine.getRPM() / engine.getGearRatio(engine.getGear());');
float topGearRPM = engine.getMaxRPM() * engine.getGearRatio(engine.getNumGears() - 1);
plotFloatBuf(calcGearboxSpinnerBuf, 0.f, topGearRPM*0.5f);

ImGui::TextDisabled("crank factor"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getCrankFactor(), "", 0, 3)); ImGui::NextColumn(); //float
ImGui::TextDisabled('float clutchTorque = (gearboxspinner - engine.getWheelSpin()) * engine.getClutch() * engine.getClutchForce();');
plotFloatBuf(calcClutchTorqueBuf, 0.f, 1000000);

ImGui::TextDisabled("RPM (min - max)"); ImGui::NextColumn();
ImGui::PlotLines("", rpmBuf, MAX_SAMPLES, 0, "", engine.getMinRPM(), engine.getMaxRPM()); ImGui::SameLine();
ImGui::Text(formatFloat(engine.getRPM(), "", 0, 3)); ImGui::NextColumn(); //float
ImGui::TextDisabled('float forceThreshold = 1.5f * fmax(engine.getTorque(), engine.getEnginePower()) * fabs(engine.getGearRatio(1)) // BUG? should probably be 0=global ');
plotFloatBuf(calcForceThresholdBuf, 0.f, 10*engine.getMaxRPM() * engine.getGearRatio(engine.getNumGears() - 1));

ImGui::TextDisabled("smoke"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getSmoke(), "", 0, 3)); ImGui::NextColumn(); //float
ImGui::TextDisabled("torque"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getTorque(), "", 0, 3)); ImGui::NextColumn(); //float
ImGui::TextDisabled("turbo PSI"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getTurboPSI(), "", 0, 3)); ImGui::NextColumn(); //float
ImGui::TextDisabled("auto mode"); ImGui::NextColumn(); ImGui::Text(''+engine.getAutoMode() ); ImGui::NextColumn(); //SimGearboxMode
ImGui::TextDisabled("gear"); ImGui::NextColumn(); ImGui::Text(''+engine.getGear() ); ImGui::NextColumn(); //int
ImGui::TextDisabled("gear range"); ImGui::NextColumn(); ImGui::Text(''+engine.getGearRange() ); ImGui::NextColumn(); //int
ImGui::TextDisabled("is running"); ImGui::NextColumn(); ImGui::Text(''+engine.isRunning() ); ImGui::NextColumn(); //bool
ImGui::TextDisabled("has contact"); ImGui::NextColumn(); ImGui::Text(''+engine.hasContact() ); ImGui::NextColumn(); //bool
ImGui::TextDisabled("cur engine torque"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getCurEngineTorque(), "", 0, 3)); ImGui::NextColumn(); //float
ImGui::TextDisabled("input shaft RPM"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getInputShaftRPM(), "", 0, 3)); ImGui::NextColumn(); //float
ImGui::TextDisabled("drive ratio"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getDriveRatio(), "", 0, 3)); ImGui::NextColumn(); //float
ImGui::TextDisabled("engine power"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getEnginePower(), "", 0, 3)); ImGui::NextColumn(); //float
//ImGui::TextDisabled(""); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getEnginePower(float) //float
ImGui::TextDisabled("turbo power"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getTurboPower(), "", 0, 3)); ImGui::NextColumn(); //float
ImGui::TextDisabled("idle mix"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getIdleMixture(), "", 0, 3)); ImGui::NextColumn(); //float
ImGui::TextDisabled("prime mix"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getPrimeMixture(), "", 0, 3)); ImGui::NextColumn(); //float
ImGui::TextDisabled("auto shift"); ImGui::NextColumn(); ImGui::Text(''+engine.getAutoShift() ); ImGui::NextColumn(); //autoswitch
ImGui::TextDisabled("acc to hold RPM"); ImGui::NextColumn(); ImGui::Text(formatFloat(engine.getAccToHoldRPM() , "", 0, 3)); ImGui::NextColumn(); //float
ImGui::Columns(1);
ImGui::TextDisabled('float clutchTorqueClamped = fclamp(clutchTorque, -forceThreshold, forceThreshold);');
plotFloatBuf(calcClutchTorqueClampedBuf, 100.f, topGearRPM*10);

ImGui::TextDisabled('float clutchTorqueFinal = clutchTorqueClamped * (1.f - fexp(-fabs(gearboxspinner - engine.getWheelSpin())));');
plotFloatBuf(calcClutchTorqueFinalBuf, 100.f, topGearRPM*10);
}
}

float fmax(float a, float b)
{
return (a > b) ? a : b;
}

float fabs(float a)
{
return a > 0.f ? a : -a;
}

float fclamp(float val, float minv, float maxv)
{
return val < minv ? minv : (val > maxv) ? maxv : val;
}

float fexp(float val)
{
const float eConstant = 2.71828183;
return pow(eConstant, val);
}
12 changes: 1 addition & 11 deletions source/main/gameplay/EngineSim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ void EngineSim::UpdateEngineSim(float dt, int doUpdate)
float force_threshold = 1.5f * std::max(m_engine_torque, getEnginePower()) * std::abs(m_gear_ratios[2]);
float gearboxspinner = m_cur_engine_rpm / m_gear_ratios[m_cur_gear + 1];
m_cur_clutch_torque = (gearboxspinner - m_cur_wheel_revolutions) * m_cur_clutch * m_clutch_force;
m_cur_clutch_torque = Math::Clamp(m_cur_clutch_torque, -force_threshold, +force_threshold);
m_cur_clutch_torque = Math::Clamp(m_cur_clutch_torque, -force_threshold, +force_threshold);
m_cur_clutch_torque *= 1.0f - approx_exp(-std::abs(gearboxspinner - m_cur_wheel_revolutions));
}
else
Expand Down Expand Up @@ -979,16 +979,6 @@ float EngineSim::getCrankFactor()
return crankfactor;
}

void EngineSim::setClutch(float clutch)
{
m_cur_clutch = clutch;
}

float EngineSim::getClutch()
{
return m_cur_clutch;
}

void EngineSim::toggleContact()
{
m_contact = !m_contact;
Expand Down
5 changes: 3 additions & 2 deletions source/main/gameplay/EngineSim.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class EngineSim : public RefCountingObject<EngineSim>
/// @name General state getters
/// @{
float getAcc();
float getClutch();
float getClutch() const { return m_cur_clutch; };
float getCrankFactor();
float getRPM() { return m_cur_engine_rpm; }
float getSmoke();
Expand All @@ -109,6 +109,7 @@ class EngineSim : public RefCountingObject<EngineSim>
float getPrimeMixture();
int getAutoShift();
float getAccToHoldRPM(); //!< estimate required throttle input to hold the current rpm
float getWheelSpin() const { return m_cur_wheel_revolutions; } //!< Wheel RPM
/// @}

/// @name Shifting diagnostic
Expand All @@ -128,7 +129,7 @@ class EngineSim : public RefCountingObject<EngineSim>
void pushNetworkState(float engine_rpm, float acc, float clutch, int gear, bool running, bool contact, char auto_mode, char auto_select = -1);
void setAcc(float val);
void autoSetAcc(float val);
void setClutch(float clutch);
void setClutch(float clutch) { m_cur_clutch = clutch; }
void setRPM(float rpm);
void setWheelSpin(float rpm);
void setAutoMode(SimGearboxMode mode);
Expand Down
1 change: 1 addition & 0 deletions source/main/scripting/bindings/EngineSimAngelscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ void RoR::RegisterEngineSim(asIScriptEngine* engine)
r = engine->RegisterObjectMethod("EngineSimClass", "float getPrimeMixture()", asMETHOD(EngineSim, getPrimeMixture), asCALL_THISCALL); ROR_ASSERT(r >= 0);
r = engine->RegisterObjectMethod("EngineSimClass", "autoswitch getAutoShift()", asMETHOD(EngineSim, getAutoShift), asCALL_THISCALL); ROR_ASSERT(r >= 0);
r = engine->RegisterObjectMethod("EngineSimClass", "float getAccToHoldRPM()", asMETHOD(EngineSim, getAccToHoldRPM), asCALL_THISCALL); ROR_ASSERT(r >= 0);
r = engine->RegisterObjectMethod("EngineSimClass", "float getWheelSpin()", asMETHOD(EngineSim, getWheelSpin), asCALL_THISCALL); ROR_ASSERT(r >= 0);

// > shifting diagnostic
r = engine->RegisterObjectMethod("EngineSimClass", "float getPostShiftClock()", asMETHOD(EngineSim, getPostShiftClock), asCALL_THISCALL); ROR_ASSERT(r >= 0);
Expand Down

0 comments on commit f20db9e

Please sign in to comment.