Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/sr2echa/TF2-Source-Code/llms.txt

Use this file to discover all available pages before exploring further.

TF2 physics are powered by VPhysics, a Source Engine wrapper around the IVP physics library. The public interface is IPhysicsEnvironment (public/vphysics_interface.h), and the implementation lives in vphysics/. Game code creates physics objects from collision models (.phy files, compiled from .qc + convex hull data) and registers them with the environment for simulation.

IPhysicsEnvironment

IPhysicsEnvironment is the simulation context. Each game level gets one environment. It steps at 60Hz by default (sv_phys_timescale).
// vphysics/physics_environment.h
class CPhysicsEnvironment : public IPhysicsEnvironment
{
public:
    // Object creation
    IPhysicsObject *CreatePolyObject( const CPhysCollide *pCollisionModel,
        int materialIndex, const Vector &position,
        const QAngle &angles, objectparams_t *pParams );

    // Simulation
    void Simulate( float deltaTime );
    void SetGravity( const Vector &gravityVector );
    float GetSimulationTimestep() const;
    void SetSimulationTimestep( float timestep );

    // Constraints
    IPhysicsConstraint *CreateHingeConstraint( ... );
    IPhysicsConstraint *CreateRagdollConstraint( ... );
    IPhysicsConstraint *CreateFixedConstraint( ... );
    IPhysicsConstraint *CreateSpring( ... );
};

Physics objects

IPhysicsObject represents a single simulated rigid body. Game entities interact with physics objects through CPhysicsProp (game/server/props.cpp) and CBaseEntity::VPhysicsGetObject(). Key unit conversions (from public/vphysics_interface.h):
  • Coordinates: Source units (1 unit = 1 inch)
  • Mass: kilograms
  • Density: kg/m³ (water ≈ 998)
  • Forces applied as impulses: kg·in/s
// Applying an impulse (e.g., explosion force)
IPhysicsObject *pPhys = pEntity->VPhysicsGetObject();
if ( pPhys )
{
    Vector impulse = direction * force;  // kg*in/s
    pPhys->ApplyForceCenter( impulse );
}

Ragdoll physics

Player death triggers a ragdoll (CRagdollProp, game/server/physics_prop_ragdoll.cpp). The ragdoll is built from the player’s current bone positions, with per-bone physics objects connected by IPhysicsConstraint ragdoll constraints.
// game/server/physics_prop_ragdoll.h
class CRagdollProp : public CBaseAnimating, public CDefaultPlayerPickupVPhysics
{
public:
    void InitRagdoll( const Vector &forceVector, int forceBone,
        const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1,
        float dt, int collisionGroup, bool activateRagdoll );

    ragdoll_t   m_ragdoll;   // array of physics objects + constraints
};

Constraints

VPhysics supports several constraint types used throughout TF2:
ConstraintUsage
CreateRagdollConstraintPer-joint limits in ragdolls
CreateHingeConstraintDoors, rotating props
CreateFixedConstraintWelded props
CreateSpringRope/spring physics
CreateLengthConstraintMax-distance rope
CreatePulleyConstraintPulley systems

Vehicle controller

IPhysicsVehicleController drives prop_vehicle_* entities. TF2 uses this for the bumper car vehicle in the Halloween Carnival of Carnage event (physics_vehicle.cpp, vphysics/physics_vehicle.h). The vehicle controller wraps an IVP raycast vehicle model.

Collision materials

Surface material properties (friction, elasticity, density) are defined in scripts/surfaceproperties.txt and loaded via IPhysicsSurfaceProps. Materials govern collision sound effects and damage modifiers for physics impacts.
VPhysics runs on the server only. Client-side physics (clientside props, debris) use a separate lightweight simulation in physpropclientside.cpp that does not synchronize with the server.

Build docs developers (and LLMs) love