Files
DoomRTX/neo/prey/Prey/force_converge.cpp
2026-05-05 15:01:01 -07:00

174 lines
5.8 KiB
C++

#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
CLASS_DECLARATION( idForce, hhForce_Converge )
END_CLASS
hhForce_Converge::hhForce_Converge( void ) {
restoreFactor = 1.0f;
restoreForceSlack = 1.0f;
restoreTime = 0.1f;
ent = NULL;
physics = NULL;
axisEnt = NULL;
bShuttle = false;
}
hhForce_Converge::~hhForce_Converge( void ) {
}
void hhForce_Converge::Save(idSaveGame *savefile) const {
ent.Save(savefile);
axisEnt.Save(savefile);
savefile->WriteVec3( target );
savefile->WriteVec3( offset );
savefile->WriteInt( bodyID );
savefile->WriteFloat( restoreTime );
savefile->WriteFloat( restoreFactor );
savefile->WriteFloat( restoreForceSlack );
savefile->WriteBool( bShuttle );
}
void hhForce_Converge::Restore( idRestoreGame *savefile ) {
ent.Restore(savefile);
axisEnt.Restore(savefile);
savefile->ReadVec3( target );
savefile->ReadVec3( offset );
savefile->ReadInt( bodyID );
savefile->ReadFloat( restoreTime );
savefile->ReadFloat( restoreFactor );
savefile->ReadFloat( restoreForceSlack );
savefile->ReadBool( bShuttle );
physics = NULL; // HUMANHEAD mdl: Updated each frame
}
void hhForce_Converge::Evaluate( int time ) {
// Get the physics of ent each frame, in case their physics object was changed.
physics = ent.IsValid() ? ent->GetPhysics() : NULL;
// Apply convergent force
if (physics) {
idVec3 p = physics->GetOrigin( bodyID ) + offset * physics->GetAxis( bodyID );
idVec3 x = p - target;
if (axisEnt.IsValid()) {
idBounds bounds = ent->GetPhysics()->GetBounds();
idVec3 rightPt = ent->GetOrigin() + (ent->GetAxis()[0] * bounds[0].x);
idVec3 axisRightPt = axisEnt->GetOrigin() + (axisEnt->GetAxis()[1] * bounds[1].x);
idVec3 leftPt = ent->GetOrigin() + (ent->GetAxis()[0] * bounds[1].x);
idVec3 axisLeftPt = axisEnt->GetOrigin() + (axisEnt->GetAxis()[1] * bounds[0].x);
//gameRenderWorld->DebugLine(idVec4(1, 0, 0, 1), rightPt, axisRightPt, 100);
p = rightPt;
x = p - axisRightPt;
x *= restoreForceSlack; //allow a linear buildup based on the distance of the target point
idVec3 v = physics->GetLinearVelocity();
float m = physics->GetMass();
float b = idMath::Sqrt(4*restoreFactor*m);
idVec3 force = -restoreFactor*x - b*v; // use with addforce, k=200000
physics->AddForce(bodyID, p, force * 0.5f ); // Great to show mass variations
//gameRenderWorld->DebugLine(idVec4(1, 0, 0, 1), leftPt, axisLeftPt, 100);
p = leftPt;
x = p - axisLeftPt;
x *= restoreForceSlack; //allow a linear buildup based on the distance of the target point
force = axisLeftPt - leftPt;
force *= m * 4;
physics->AddForce(bodyID, p, force ); // Great to show mass variations
return;
}
x *= restoreForceSlack; //allow a linear buildup based on the distance of the target point
if (ent->IsType(idAFEntity_Base::Type)) { // Actors use velocity method since their masses are unrealistic, ragdolls need it too
if (!ent->fl.tooHeavyForTractor) {
// Velocity method: cover distance in fixed time
idVec3 velocity = -x / restoreTime; // Use with SetLinearVelocity()
if (ent->IsType(idActor::Type)) { //if a player is affected by this force..
//..do not allow him to build up velocity into his ground plane
if (ent->GetPhysics()->IsType(idPhysics_Player::Type) && ent->GetPhysics()->HasGroundContacts()) {
velocity.x *= -ent->GetPhysics()->GetGravityNormal().x;
velocity.y *= -ent->GetPhysics()->GetGravityNormal().y;
velocity.z *= -ent->GetPhysics()->GetGravityNormal().z;
}
}
physics->SetLinearVelocity(velocity, bodyID);
}
else {
// Entities that are too heavy get no force, just give feedback force
}
} else {
float m = physics->GetMass();
if (bShuttle && m < 1500.0f) { // Different equation for picking up low mass objects with the shuttle
idVec3 v = physics->GetLinearVelocity();
float springFactor = restoreFactor*0.0002f;
float dampFactor = idMath::Sqrt(springFactor);
idVec3 force = (-x * springFactor * m) - (v * dampFactor * m);
physics->AddForce(bodyID, p, force );
} else { // Critically Damped spring: m*a = -k*x - b*v ; b = 2 * sqrt(m*k)
idVec3 v = physics->GetLinearVelocity();
float m = physics->GetMass();
float b = idMath::Sqrt(4.0f*restoreFactor*m);
idVec3 force = -restoreFactor*x - b*v; // use with addforce, k=200000
physics->AddForce(bodyID, p, force ); // Great to show mass variations
}
}
/* else { // Impulse method
idVec3 v = physics->GetLinearVelocity();
float b = idMath::Sqrt(4*restoreFactor);
impulse = -restoreFactor*x - b*v; // Use with applyimpulse, k=50000
physics->ApplyImpulse(bodyID, p, impulse ); // Worked for all but some moveables (k=50000)
}
else { // Mass scaled force method, applies varying force to keep constant velocity
idVec3 v = physics->GetLinearVelocity();
float m = physics->GetMass();
float b = idMath::Sqrt(4*restoreFactor);
impulse = (-restoreFactor*x - b*v) * m; // use with addforce, k=500
physics->AddForce(bodyID, p, impulse ); // Works for all but ragdolls (k=500)
}
}*/
}
}
void hhForce_Converge::RemovePhysics( const idPhysics *phys ) {
// physics of ent is stored each evaluate so we can compare pointers directly, rather than querying
// ent about it's physics. This is done because typically, physics objects are reported as removed
// during deconstruction of the entities.
if (ent.IsValid() && phys == physics) {
SetEntity(NULL);
}
}
void hhForce_Converge::SetRestoreTime( float time ) {
restoreTime = idMath::ClampFloat(0.02f, time, time);
}
void hhForce_Converge::SetTarget(idVec3 &newTarget) {
target = newTarget;
}
void hhForce_Converge::SetEntity(idEntity *entity, int id, const idVec3 &point) {
ent = entity;
bodyID = id;
offset = point;
physics = NULL;
}
void hhForce_Converge::SetAxisEntity(idEntity *entity) {
axisEnt = entity;
}