Skip to content

Commit a56d49a

Browse files
committed
Fixed inaccurate emitter impulse estimation, causing severe AI problems with certain actors
1 parent 1827c71 commit a56d49a

File tree

4 files changed

+47
-19
lines changed

4 files changed

+47
-19
lines changed

Source/Entities/AEmitter.cpp

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -271,32 +271,39 @@ float AEmitter::EstimateImpulse(bool burst) {
271271
// Calculate the impulse generated by the emissions, once and store the result
272272
if ((!burst && m_AvgImpulse < 0) || (burst && m_AvgBurstImpulse < 0)) {
273273
float impulse = 0.0F;
274-
float velMin, velMax, velRange, spread;
275274

276275
// Go through all emissions and emit them according to their respective rates
277276
for (Emission* emission: m_EmissionList) {
278277
// Only check emissions that push the emitter
279278
if (emission->PushesEmitter()) {
279+
// Todo... we're not checking emission start/stop times here, so this will always calculate the impulse as if the emission was active.
280+
// There's not really an easy way to do this, since the emission rate is not necessarily constant over time.
280281
float emissions = (emission->GetRate() / 60.0f) * g_TimerMan.GetDeltaTimeSecs();
281282
float scale = 1.0F;
282283
if (burst) {
283284
emissions *= emission->GetBurstSize();
284285
scale = m_BurstScale;
285286
}
286287

287-
velMin = emission->GetMinVelocity() * scale;
288-
velRange = (emission->GetMaxVelocity() - emission->GetMinVelocity()) * 0.5F * scale;
289-
spread = (std::max(static_cast<float>(c_PI) - emission->GetSpread(), 0.0F) / c_PI) * scale; // A large spread will cause the forces to cancel eachother out
288+
if (emissions > 0) {
289+
int extraEmissions = emission->GetParticleCount() - 1;
290+
emissions += extraEmissions;
291+
}
292+
293+
float velMin = emission->GetMinVelocity() * scale;
294+
float velRange = (emission->GetMaxVelocity() - emission->GetMinVelocity()) * scale * 0.5f;
295+
float spread = (std::max(static_cast<float>(c_PI) - (emission->GetSpread() * scale), 0.0F) / c_PI); // A large spread will cause the forces to cancel eachother out
290296

291297
// Add to accumulative recoil impulse generated, F = m * a.
292298
impulse += (velMin + velRange) * spread * emission->m_pEmission->GetMass() * emissions;
293299
}
294300
}
295301

296-
if (burst)
302+
if (burst) {
297303
m_AvgBurstImpulse = impulse;
298-
else
304+
} else {
299305
m_AvgImpulse = impulse;
306+
}
300307
}
301308

302309
// Scale the emission rate up or down according to the appropriate throttle multiplier.
@@ -411,9 +418,10 @@ void AEmitter::Update() {
411418
// Start timing until next burst
412419
m_BurstTimer.Reset();
413420
}
414-
// Not enough spacing, cancel the triggering if there was any
415-
else
421+
else {
422+
// Not enough spacing, cancel the triggering if there was any
416423
m_BurstTriggered = false;
424+
}
417425

418426
int emissionCountTotal = 0;
419427
float velMin, velRange, spread;
@@ -448,7 +456,7 @@ void AEmitter::Update() {
448456
float scale = 1.0F;
449457
// Add extra emissions if bursting.
450458
if (m_BurstTriggered) {
451-
emissionCount += emission->GetBurstSize() * std::floor(throttleFactor);
459+
emissionCount += emission->GetBurstSize();
452460
scale = m_BurstScale;
453461
}
454462
emissionCountTotal += emissionCount;
@@ -515,7 +523,14 @@ void AEmitter::Update() {
515523
m_LastEmitTmr.Reset();
516524

517525
// Apply recoil/push effects. Joint stiffness will take effect when these are transferred to the parent.
518-
if (!pushImpulses.IsZero()) {
526+
static bool enableFakedImpulse = false; // useful for debugging the accuracy of EstimateImpulse();
527+
if (enableFakedImpulse) {
528+
Vector fakeImpulse;
529+
fakeImpulse.SetXY(-EstimateImpulse(m_BurstTriggered), 0.0F);
530+
fakeImpulse.RadRotate(m_EmitAngle.GetRadAngle());
531+
fakeImpulse = RotateOffset(fakeImpulse);
532+
AddImpulseForce(fakeImpulse);
533+
} else {
519534
AddImpulseForce(pushImpulses);
520535
}
521536

Source/Entities/MovableObject.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,10 +728,13 @@ void MovableObject::AddAbsForce(const Vector& force, const Vector& absPos) {
728728
}
729729

730730
void MovableObject::AddAbsImpulseForce(const Vector& impulse, const Vector& absPos) {
731+
if (impulse.IsZero()) {
732+
return;
733+
}
734+
731735
#ifndef RELEASE_BUILD
732736
RTEAssert(impulse.GetLargest() < 500000, "HUEG IMPULSE FORCE");
733737
#endif
734-
735738
m_ImpulseForces.push_back(std::make_pair(impulse, g_SceneMan.ShortestDistance(m_Pos, absPos) * c_MPP));
736739
}
737740

Source/Entities/MovableObject.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,12 +628,14 @@ namespace RTE {
628628
/// @param offset A Vector with the offset, in METERS, of where the impulse is being (default: Vector())
629629
/// applied relative to the center of this MovableObject.
630630
void AddImpulseForce(const Vector& impulse, const Vector& offset = Vector()) {
631+
if (impulse.IsZero()) {
632+
return;
633+
}
631634

632635
#ifndef RELEASE_BUILD
633636
RTEAssert(impulse.MagnitudeIsLessThan(500000.0F), "HUEG IMPULSE FORCE");
634637
RTEAssert(offset.MagnitudeIsLessThan(5000.0F), "HUGE IMPULSE FORCE OFFSET");
635638
#endif
636-
637639
m_ImpulseForces.push_back({impulse, offset});
638640
}
639641

Source/Entities/PEmitter.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -227,39 +227,47 @@ float PEmitter::EstimateImpulse(bool burst) {
227227
// Calculate the impulse generated by the emissions, once and store the result
228228
if ((!burst && m_AvgImpulse < 0) || (burst && m_AvgBurstImpulse < 0)) {
229229
float impulse = 0.0F;
230-
float velMin, velMax, velRange, spread;
231230

232231
// Go through all emissions and emit them according to their respective rates
233232
for (Emission* emission: m_EmissionList) {
234233
// Only check emissions that push the emitter
235234
if (emission->PushesEmitter()) {
235+
// Todo... we're not checking emission start/stop times here, so this will always calculate the impulse as if the emission was active.
236+
// There's not really an easy way to do this, since the emission rate is not necessarily constant over time.
236237
float emissions = (emission->GetRate() / 60.0f) * g_TimerMan.GetDeltaTimeSecs();
237238
float scale = 1.0F;
238239
if (burst) {
239240
emissions *= emission->GetBurstSize();
240241
scale = m_BurstScale;
241242
}
242243

243-
velMin = emission->GetMinVelocity() * scale;
244-
velRange = (emission->GetMaxVelocity() - emission->GetMinVelocity()) * 0.5F * scale;
245-
spread = (std::max(static_cast<float>(c_PI) - emission->GetSpread(), 0.0F) / c_PI) * scale; // A large spread will cause the forces to cancel eachother out
244+
if (emissions > 0) {
245+
int extraEmissions = emission->GetParticleCount() - 1;
246+
emissions += extraEmissions;
247+
}
248+
249+
float velMin = emission->GetMinVelocity() * scale;
250+
float velRange = (emission->GetMaxVelocity() - emission->GetMinVelocity()) * scale * 0.5f;
251+
float spread = (std::max(static_cast<float>(c_PI) - (emission->GetSpread() * scale), 0.0F) / c_PI); // A large spread will cause the forces to cancel eachother out
246252

247253
// Add to accumulative recoil impulse generated, F = m * a.
248254
impulse += (velMin + velRange) * spread * emission->m_pEmission->GetMass() * emissions;
249255
}
250256
}
251257

252-
if (burst)
258+
if (burst) {
253259
m_AvgBurstImpulse = impulse;
254-
else
260+
} else {
255261
m_AvgImpulse = impulse;
262+
}
256263
}
257264

258265
// Scale the emission rate up or down according to the appropriate throttle multiplier.
259266
float throttleFactor = GetThrottleFactor();
260267
// Apply the throttle factor to the emission rate per update
261-
if (burst)
268+
if (burst) {
262269
return m_AvgBurstImpulse * throttleFactor;
270+
}
263271

264272
return m_AvgImpulse * throttleFactor;
265273
}

0 commit comments

Comments
 (0)