|
|
@@ -841,6 +841,79 @@ float fSeaPlaneWaterResistance = 30.0f; |
|
|
void |
|
|
CBoat::ApplyWaterResistance(void) |
|
|
{ |
|
|
#ifdef FIX_BUGS |
|
|
// TODO: confirm if the explanation below makes sense |
|
|
float depthResistance = 0.001f * pHandling->fSuspensionForceLevel * SQR(m_fVolumeUnderWater) * m_fMass; |
|
|
if(GetModelIndex() == MI_SKIMMER) |
|
|
depthResistance *= fSeaPlaneWaterResistance; |
|
|
float fwdSpeed = DotProduct(GetMoveSpeed(), GetForward()); |
|
|
|
|
|
// Water resistances goes up with the square of boat speed (in real life it goes up by the |
|
|
// cube? close enough!). An extra 0.05f fudge factor was probably put in to make sure the |
|
|
// boat still has resistance at low speeds (ie auto-brakes to standstill). |
|
|
float waterResistance = (SQR(fwdSpeed) + 0.05f) * Abs(depthResistance); // Abs() used defensively, negative numbers stuff things up later |
|
|
// waterResistance will now be a small number like 0.002 or 0.015 |
|
|
|
|
|
// An odd use of Abs() was in the original binary. It's possible that the developers did not |
|
|
// put this in intentionally, instead the compiler may have silently added it to avoid |
|
|
// Pow() having to deal with negative numbers to a fractional power (undefined) later. |
|
|
// Regardless it was done badly, making assumptions like vecMoveRes never accidentally |
|
|
// being negative, so the use of Abs() has changed a little bit in this FIX_BUGS. In |
|
|
// real gameplay these corner cases should rarely (never?) be encountered anyway. |
|
|
|
|
|
// Our boat has different water resistances when travelling forwards (y axis) versus |
|
|
// sideways (x axis). Boats tend to find it hard to move sideways. |
|
|
float rx = Abs(pBoatHandling->vecMoveRes.x/(waterResistance + 1.0f)); // Abs() used defensively, negative numbers stuff things up later |
|
|
float ry = Abs(pBoatHandling->vecMoveRes.y/(waterResistance + 1.0f)); |
|
|
float rz = Abs(pBoatHandling->vecMoveRes.z/(waterResistance + 1.0f)); |
|
|
// These rx, ry, rz resistance numbers will each be something like 0.8 or 0.9 or so |
|
|
|
|
|
// Fun fact: the above equations are _approximately_ the same as: |
|
|
// |
|
|
// pBoatHandling->vecMoveRes.x * (1.0f - waterResistance) |
|
|
// |
|
|
// If you change the equations to this then boating feels about the same in-game. |
|
|
// Which version makes more sense compared to physics in real life? Probably neither :P |
|
|
// This second version of the equation is a little more efficient however (no division). |
|
|
|
|
|
// Now how do we apply these rx ry rz resistance numbers to the boat speed? |
|
|
// It's not simple: |
|
|
// |
|
|
// - We can't multiply them into the speed once per frame, because then players with |
|
|
// higher framerates will get a lot more friction when boating (lower top speed). |
|
|
// |
|
|
// - We can't linearly modify each r number based off frametime, as higher FPS players |
|
|
// will still end up with more friction. This is for the same reason why linearly |
|
|
// reducing your bank account's yearly interest into monthly amounts but then |
|
|
// compounding it monthly will yield you more money than just compounding it yearly. |
|
|
// |
|
|
// - We could try compounding each r number based off how many fixed units of time have |
|
|
// passed (eg multiply itself by itself for every 1ms elapsed this frame). This will |
|
|
// work fairly regardless of framerate. |
|
|
// |
|
|
// We don't actually have to limit ourselves to a fixed time unit (like 1ms chunks), |
|
|
// instead we can raise the resistance to some power of time using Pow(). |
|
|
float rrx = Pow(rx, 0.5f*CTimer::GetTimeStep()); // Why 0.5f? Taste? |
|
|
float rry = Pow(ry, 0.5f*CTimer::GetTimeStep()); |
|
|
float rrz = Pow(rz, 0.5f*CTimer::GetTimeStep()); |
|
|
|
|
|
m_vecMoveSpeed = Multiply3x3(m_vecMoveSpeed, GetMatrix()); // convert velocities to boat-local space (y = boat forwards, x = sideways, z = up/down) |
|
|
m_vecMoveSpeed.x *= rrx; |
|
|
m_vecMoveSpeed.y *= rry; |
|
|
m_vecMoveSpeed.z *= rrz; |
|
|
float force = (rry - 1.0f) * m_vecMoveSpeed.y * m_fMass; |
|
|
m_vecMoveSpeed = Multiply3x3(GetMatrix(), m_vecMoveSpeed); // back to world space |
|
|
|
|
|
// Is this for "flipping the boat over"? Seems to have almost zero effect normally? |
|
|
ApplyTurnForce(force*GetForward(), -GetUp()); |
|
|
|
|
|
// What the hell? Why arbitrarily compound in one more factor of rrz? |
|
|
// This is framerate dependent! Bah! |
|
|
if(m_vecMoveSpeed.z > 0.0f) |
|
|
m_vecMoveSpeed.z *= rrz; |
|
|
else |
|
|
m_vecMoveSpeed.z *= (1.0f - rrz)*0.5f + rrz; |
|
|
#else |
|
|
// TODO: figure out how this works |
|
|
float resistance = 0.001f * pHandling->fSuspensionForceLevel * SQR(m_fVolumeUnderWater) * m_fMass; |
|
|
if(GetModelIndex() == MI_SKIMMER) |
|
|
@@ -865,6 +938,7 @@ CBoat::ApplyWaterResistance(void) |
|
|
m_vecMoveSpeed.z *= fz; |
|
|
else |
|
|
m_vecMoveSpeed.z *= (1.0f - fz)*0.5f + fz; |
|
|
#endif |
|
|
} |
|
|
|
|
|
RwObject* |
|
|
|