unfurl

Technical Documentation

NsVehicles

Architecture

Modules

The descriptor is NsVehicle.uplugin. It has two modules. Both are on Win64, Mac, IOS, Android, and Linux only.

Module Type Loading phase Content
AsyncTickPhysics Runtime Default AAsyncTickPawn, UAsyncTickActorComponent, the Chaos sim callback that calls them, and UAsyncTickFunctions for physics thread force and velocity calls
NsVehicle Runtime Default The vehicle pawn, the modules, the wheels, the interior parts, the articulated part, and the AI steering

AsyncTickPhysics is bundled in Source/ThirdParty/AsyncTickPhysics/Source/AsyncTickPhysics/. It has no descriptor of its own. NsVehicle.uplugin lists it.

Folders

All folders are under Source/NsVehicle/Public/ and Source/NsVehicle/Private/. Both use the same layout.

Folder Classes
(root) FNsVehicleModule in NsVehicleModule.h. Its startup and shutdown are empty
Vehicle/ ANsVehicle, and NsVehicleTypes.h with the shared enums and structs
Modules/ UNsVehicleModuleComponent, the base class of all modules
Modules/Control/ UNsVehicleControlsComponent
Modules/Powertrain/ UNsVehicleEngineComponent, UNsVehicleTransmissionComponent, UNsVehicleDrivetrainComponent
Modules/Chassis/ UNsVehicleBrakeComponent, UNsVehicleSteeringComponent, UNsVehicleBodyDynamicsComponent, UNsVehicleAerodynamicsComponent, UNsVehicleAirControlComponent, UNsVehicleAntiGravityComponent, UNsVehicleIdleLockComponent
Modules/Network/ UNsVehicleNetworkComponent
Modules/Animation/ UNsVehicleAnimationComponent
Wheels/ UNsVehicleSuspensionComponent, UNsVehicleStaticWheel, UNsVehicleWheel
Interior/ UNsVehicleInteriorComponent (abstract) and its six subclasses
Articulation/ UNsVehicleArticulatedComponent
AI/ UNsVehicleAI

Main Classes

Physics Step Order

The AsyncTickPhysics sim callback calls ANsVehicle::NativeAsyncTick in OnPreSimulate_Internal, one time for each physics step:

  1. AAsyncTickPawn::NativeAsyncTick, which runs the Blueprint AsyncTick event.
  2. UpdateGroundContact. With the drivetrain on, Drivetrain->UpdateWheelSlip averages the slip, and the vehicle is airborne when no driven wheel is on the ground. Otherwise the vehicle counts airborne wheels against InAirWheelCount. Detached wheels do not count.
  3. UpdateAngularMotion: the yaw rate and the yaw acceleration.
  4. IdleLock->UpdateIdleLock.
  5. The branch on Network->GetReplicationMethod(). The Networking section gives each branch.
  6. UpdateWheelPhysics: each suspension component gets the wheel torque and the inputs, then runs its trace and forces.

UpdatePhysicsCore:

  1. Reads the physics transform with ATP_GetTransform.
  2. Standard powertrain (UpdateStandardPowertrain): Engine torque, Transmission gear ratio and automatic shift, engine brake force, then on the ground: Brakes force, Drivetrain effective power, drive force and drive pitch torque, BodyDynamics pitch. Then Aerodynamics drag, Engine RPM, and Transmission shift timers. If the torque curve is missing, UpdatePhysicsCore returns at once and applies no force in that step.
  3. Arcade powertrain (UpdateArcadePowertrain): Engine arcade torque, Brakes arcade force, external resistance, then on the ground: drive force and BodyDynamics pitch.
  4. Steering drift torque, on the ground only.
  5. UpdateMotionState: local velocity, speed, and acceleration.
  6. Brakes handbrake, AirControl, AntiGravity, and BodyDynamics lean steer.

The drive force acts at the body center of mass through ATP_AddForce. The wheel torque does not move the vehicle. It only feeds the slip model of the driven wheels.

Game Thread Order

ANsVehicle::Tick:

  1. WakeAllRigidBodies, if bAutoWakeRigidBodies is true.
  2. UpdateAttachedComponents: Steering sends the input and the response speed to the steering wheels. Each suspension component places, steers, and spins its wheel, and draws its debug shapes. Then the interior and articulated parts update.
  3. Network->UpdateFastSync.
  4. AntiGravity->UpdateGameThread.
  5. The game thread local velocity for GetSideSlipAngleGT.
  6. Animation->UpdateLocationVelocity, and SpinSuspensionWheels in animation mode.

Data Flow

The modules do not hold pointers to each other. They read other modules through the vehicle getters, for example GetVehicle()->GetTransmission(). The vehicle passes the physics body, the direction vectors, and the inputs as arguments.

The physics thread and the game thread share the vehicle and module state with no lock. For example, the Controls setters run on the game thread, and the physics step reads the same fields.

The arcade powertrain uses the active gear ratio (3) and the active differential ratio (3.15). Only SetCurrentGearRatio and SetDifferentialRatio change them. The Differential Ratio property applies to the standard powertrain only.

Lifetime

  1. The NsVehicle module and the AsyncTickPhysics module load in the Default phase.
  2. FAsyncTickPhysicsModule::StartupModule binds to FPhysicsDelegates::OnPhysSceneInit and OnPhysSceneTerm. It makes one FAsyncTickManager for each physics scene, and deletes it when the scene ends.
  3. The ANsVehicle constructor makes the 13 modules with CreateDefaultSubobject. Their subobject names are Controls, Engine, Transmission, Drivetrain, Brakes, Steering, BodyDynamics, Aerodynamics, AirControl, AntiGravity, IdleLock, Network, and Animation. It also sets the net update frequency and the minimum net update frequency to 100.
  4. Each module caches its owner in OnRegister. It logs an error if the owner is not an ANsVehicle.
  5. AAsyncTickPawn::BeginPlay adds the pawn to the async tick manager. EndPlay removes it.
  6. ANsVehicle::BeginPlay caches the root as the physics body. It finds the suspension, interior, and articulated components with GetComponents. Components added later are not in these lists.
  7. UNsVehicleSuspensionComponent::BeginPlay makes the wheel mesh with NewObject and the actor as the outer, or it uses its first child static mesh. Then it reads the wheel radius and logs setup warnings.
  8. UNsVehicleEngineComponent::BeginPlay and UNsVehicleBrakeComponent::BeginPlay store the torque and the brake force. SetEngineTorqueEnabled and SetBrakesEnabled restore these values.
  9. UNsVehicleAnimationComponent::InitializeAnimationSystem replaces the suspension list with the children of the root whose first tag is NsVehicleSuspensionComponent.

DetachWheel moves the wheel mesh out of the attachment tree and makes it simulate. The actor still owns the wheel mesh, so the wheel mesh is destroyed with the vehicle. ReattachWheel stops its physics, turns its collision off, and attaches it to the suspension component again.

Extension Points

Module replacement is not supported. ANsVehicle has no FObjectInitializer constructor, and the module physics functions are not virtual.

Dependencies

Dependency Kind Why
Core, CoreUObject, Engine Public, NsVehicle Base types, components, and physics
AsyncTickPhysics Public, NsVehicle ANsVehicle derives from AAsyncTickPawn and calls UAsyncTickFunctions
Slate, SlateCore Private, NsVehicle Listed in NsVehicle.Build.cs. No NsVehicle source file uses them
Core Public, AsyncTickPhysics Base types
CoreUObject, Engine, Slate, SlateCore, Chaos Private, AsyncTickPhysics Physics scene delegates and the Chaos sim callback

AsyncTickPhysics.Build.cs also calls SetupModulePhysicsSupport. The .uplugin lists no plugin dependencies.

Performance

Networking

The physics step branch:

Method Server Client
Full UpdatePhysicsCore, AsyncTick, ServerStateSync(true) ClientStateSync(true): copies the velocities, RPM, gear, inputs, and speed
Data Only UpdatePhysicsCore, AsyncTick, ServerStateSync(false) ClientStateSync(false), then UpdatePhysicsCore and AsyncTick
None UpdatePhysicsCore, AsyncTick UpdatePhysicsCore, AsyncTick

Contact