Architecture Overview
NWH Vehicle Physics 2 uses a modular component-based architecture with VehicleController as the central hub coordinating all vehicle systems.
Component Hierarchy
VehicleController is the central hub that coordinates all vehicle systems:
VehicleController (Main Hub)
├── Powertrain
│ ├── EngineComponent (power generation)
│ ├── ClutchComponent (power transfer control)
│ ├── TransmissionComponent (gear ratios)
│ ├── DifferentialComponent(s) (torque distribution)
│ └── WheelComponent(s) (power sinks → WheelController)
├── Steering (angle calculations, speed-dependent reduction)
├── Brakes (torque application, brake distribution)
├── Input
│ └── VehicleInputHandler
│ ├── InputSystemVehicleInputProvider
│ ├── InputManagerVehicleInputProvider
│ └── MobileVehicleInputProvider
├── EffectManager
│ ├── LightsManager (headlights, brake, indicators)
│ ├── SkidmarkManager (tire marks)
│ ├── SurfaceParticleManager (dust, dirt, spray)
│ └── Exhausts (smoke, flash)
├── SoundManager
│ ├── EngineRunningComponent
│ ├── EngineStartStopComponent
│ ├── TransmissionWhineComponent
│ ├── WheelSkidComponent
│ ├── WheelTireNoiseComponent
│ └── [other sound components]
├── GroundDetection (surface type identification)
├── DamageHandler (collision damage)
└── ModuleManager
├── ABSModule
├── TCSModule
├── ESCModule
├── CruiseControlModule
├── ArcadeModule
├── MotorcycleModule
├── TrailerModule / TrailerHitchModule
├── AerodynamicsModule
├── NOSModule
└── [15+ optional modules]
VehicleComponent Lifecycle
All vehicle systems inherit from VehicleComponent, providing a standardized lifecycle. Methods are prefixed VC_ to avoid conflicts with Unity callbacks.
Lifecycle Stages
┌─────────────────────────────────────┐
│ INITIALIZATION │
└─────────────────────────────────────┘
│
VC_Initialize(VehicleController vc)
Sets parent reference
│
VC_Initialize()
Component-specific setup
│
VC_LoadStateFromStateSettings()
Apply LOD-based initial state
│
┌─────────────────────────────────────┐
│ RUNTIME LOOP │
└─────────────────────────────────────┘
│
┌───────────────┴───────────────┐
│ │
VC_Enable() VC_Disable()
Component active Component inactive
│ │
├───────────────────────────────┤
│ │
VC_FixedUpdate(dt) │
Physics updates │
│ │
VC_Update(dt) │
Visual updates │
│ │
└───────────────────────────────┘
Lifecycle Methods
| Method | When Called | Purpose |
|---|---|---|
VC_Initialize(vc) |
Once on startup | Sets VehicleController reference |
VC_Initialize() |
Once on startup | Component-specific initialization |
VC_SetDefaults() |
On first setup | Apply default configuration values |
VC_Validate() |
Editor/runtime | Validate component configuration |
VC_LoadStateFromStateSettings() |
On state change | Apply LOD-based state |
VC_Enable() |
When enabled | Activate component |
VC_Disable() |
When disabled | Deactivate component |
VC_FixedUpdate(dt) |
Each FixedUpdate | Physics calculations |
VC_Update(dt) |
Each Update | Visual/audio updates |
Example Implementation
public class CustomComponent : VehicleComponent
{
public override void VC_Initialize()
{
base.VC_Initialize();
// Setup code here
}
public override void VC_Enable()
{
base.VC_Enable();
// Called when component becomes active
}
public override void VC_FixedUpdate(float dt)
{
base.VC_FixedUpdate(dt);
if (!IsActive) return;
// Physics calculations here
}
public override void VC_Update(float dt)
{
base.VC_Update(dt);
if (!IsActive) return;
// Visual updates here
}
}
Update Order
Execution Order Configuration
NWH Vehicle Physics uses Unity's Script Execution Order to ensure proper update sequencing:
| Order | Component | Responsibility |
|---|---|---|
| 90 | VehicleController.FixedUpdate | Input, steering, brakes, wheel groups |
| 100 | WheelController.OnEnable | Register with WheelControllerManager |
| 110 | WheelControllerManager.FixedUpdate | Substep loop with powertrain callbacks |
FixedUpdate Flow
Each physics frame follows this sequence:
VehicleController.FixedUpdate() [Order 90]
├── 1. Process input states
├── 2. Update steering angles
├── 3. Calculate brake torques
├── 4. Update wheel groups
└── 5. Prepare for physics substep
WheelControllerManager.FixedUpdate() [Order 110]
├── BeginFrame()
│ └── Read Rigidbody state (position, velocity, inertia)
│
├── SUBSTEP LOOP (N iterations, typically 4)
│ ├── BeginSubstep()
│ │ └── Reset force accumulators
│ │
│ ├── ISubstepCallback.OnBeforeSubstep(dt)
│ │ └── Powertrain.IntegrateDownwards() ← Engine torque propagation
│ │
│ ├── WheelController.SubStep(dt)
│ │ ├── Ground detection
│ │ ├── Suspension forces
│ │ ├── Friction forces
│ │ └── Accumulate forces
│ │
│ ├── CoordinateStaticFrictionBreak()
│ │
│ └── EndSubstep()
│ └── Apply forces to state, integrate
│
└── EndFrame()
└── Write final velocity to Rigidbody
Update Flow
Each render frame follows this sequence:
VehicleController.Update()
├── 1. LOD distance checks
├── 2. Update sound components
├── 3. Update visual effects
└── 4. Update module visuals
VehicleController.LateUpdate()
└── 1. Camera and final visual updates
Physics Substepping
The powertrain and wheel physics run at a higher frequency than Unity's FixedUpdate through the substepping system.
How Substepping Works
Unity FixedUpdate (60Hz / 0.01667s)
│
└── WheelControllerManager
├── Substep 0 (0.00417s)
│ ├── Powertrain calculates torques
│ └── Wheel calculates forces
│
├── Substep 1 (0.00417s)
│ ├── Powertrain responds to wheel state
│ └── Wheel recalculates with new torque
│
├── Substep 2 (0.00417s)
│ └── ...
│
└── Substep 3 (0.00417s)
└── Final forces applied to Rigidbody
Configuration
The effective physics rate is calculated as:
Effective Rate = (1 / fixedDeltaTime) * substepCount
Example:
- Fixed Timestep: 0.01667s (60Hz desktop, recommended)
- Substeps: 4
- Effective Rate: 60 * 4 = 240Hz
See WheelControllerManager in the WheelController3D package documentation for detailed substepping documentation.
State System (LOD)
StateSettings provides distance-based component activation for performance optimization.
LOD Levels
| Level | Distance | Description |
|---|---|---|
| LOD 0 | Close | Full simulation, all effects/sounds |
| LOD 1 | Medium | Reduced quality, simplified physics |
| LOD 2 | Far | Minimal simulation, no effects |
| LOD 3 | Very Far | Component sleeping, minimal overhead |
State Transitions
Distance increases →
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ LOD 0 │ → │ LOD 1 │ → │ LOD 2 │ → │ LOD 3 │
│ Full │ │ Reduced │ │ Minimal │ │ Sleep │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
← Distance decreases
Per-Component State
Each VehicleComponent can define its behavior at each LOD level:
// In StateSettings ScriptableObject
public class ComponentState
{
public bool isEnabled;
public int lodLevel;
// Component-specific settings per LOD
}
See StateSettings and LOD for configuration details.
Input System Architecture
The input system uses a provider pattern for platform abstraction.
Input Flow
Hardware Input
│
▼
SceneInputProvider (scene-level)
├── InputSystemSceneInputProvider
├── InputManagerSceneInputProvider
└── MobileSceneInputProvider
│
▼
VehicleInputHandler (per-vehicle)
│
▼
VehicleInputStates
├── throttle (0-1)
├── brakes (0-1)
├── steering (-1 to 1)
├── clutch (0-1)
├── handbrake (bool)
├── shiftUp (bool)
├── shiftDown (bool)
└── [other inputs]
│
▼
Vehicle Systems
├── Powertrain (throttle, clutch, shifts)
├── Steering (steering)
├── Brakes (brakes, handbrake)
└── Modules (horn, lights, etc.)
Input Provider Types
| Provider | Platform | Input Source |
|---|---|---|
| InputSystemSceneInputProvider | Desktop/Console | Unity Input System |
| InputManagerSceneInputProvider | Desktop | Legacy Input Manager |
| MobileSceneInputProvider | Mobile | Touch controls |
| FFBInputProvider | Desktop | Force feedback wheels |
Module System
Modules are optional vehicle features that can be added, removed, or configured independently.
Module Categories
Driver Assistance:
- ABSModule - Anti-lock Braking System
- TCSModule - Traction Control System
- ESCModule - Electronic Stability Control
- CruiseControlModule - Speed maintenance
- SpeedLimiterModule - Maximum speed enforcement
Vehicle Types:
- MotorcycleModule - Lean physics
- ArcadeModule - Simplified physics
Features:
- TrailerModule / TrailerHitchModule - Towing
- AerodynamicsModule - Downforce
- NOSModule - Nitrous boost
- FuelModule - Fuel consumption
- FlipOverModule - Auto-recovery
- MetricsModule - Performance tracking
- RiggingModule - Visual bone animation
- AirSteerModule - In-air steering
Module Lifecycle
Modules follow the same VehicleComponent lifecycle but are managed through ModuleManager:
// Enable/disable modules
vc.moduleManager.SetModuleState("ABS", true);
vc.moduleManager.SetModuleState("TCS", false);
// Get module reference
var absModule = vc.moduleManager.GetModule<ABSModule>();
// Check module state
bool isActive = absModule?.IsEnabled ?? false;
Design Patterns Used
Component Pattern
All vehicle systems inherit from VehicleComponent for consistent lifecycle management.
Provider Pattern
Input system uses pluggable providers for platform abstraction.
Manager Pattern
Centralized managers coordinate related components:
ModuleManager- Optional modulesSoundManager- Audio playbackEffectManager- Visual effectsWheelControllerManager- Physics substepping
Observer Pattern
Event-based notifications for state changes:
onLODChanged- LOD level transitionsonVehicleChanged- Active vehicle switchingonActiveVehicleChanged- Global vehicle tracking
State Pattern
LOD system manages component states based on distance.
Best Practices
Initialization
- Use
VC_Initialize()for setup, not Unity'sAwake()orStart() - Access other components only after initialization
- Use
VC_SetDefaults()for default values, not field initializers
Updates
- Physics calculations go in
VC_FixedUpdate(dt) - Visual updates go in
VC_Update(dt) - Always check
if (!IsActive) return;at the start
Performance
- Enable LOD system for multiple vehicles
- Disable unused modules
- Use appropriate substep count for platform
- Pool effects (skidmarks, particles)
Debugging
- Enable gizmos to visualize wheel positions and forces
- Use Telemetry window (Window > NWH > Telemetry)
- Check Unity Profiler for bottlenecks
- Recommended Fixed Timestep: 0.01667s (60Hz) desktop, 0.0333s (30Hz) mobile
Related Documentation
- VehicleController - Main controller component
- VehicleComponent - Base component class
- Powertrain - Powertrain system
- WheelControllerManager (WheelController3D package) - Physics substepping
- StateSettings - LOD configuration
- ModuleManager - Module system