Creating custom blocks #
The modular drivetrain design in Vehicle Physics Pro uses functional Blocks to implement the internal mechanical parts of the vehicle such as engine, gearbox, etc. Blocks may be connected in any number and combination.
A block derives from VehiclePhysics.Block
. It implements the logic of the block by overriding the
virtual methods for simulating the state and torque flow within that block.
The virtual methods in VehiclePhysics.Block
and their roles are detailed in Block reference.
- Simple Block
- Parts with negligible inertia such as shafts and gears. Write the events Initialize, CheckConnections, PreStep (optional), ComputeStateUpstream and EvaluateTorqueDownstream as in the example below.
- Standard Block
-
Parts with negligible inertia following the Block Protocol for Settings, Inputs, States and Sensors. Implement the same events as in the Simple Block and apply the protocol for the exposed fields.
The Differential block is an example of standard block.
- Inertial Block
-
Parts with noticeable inertia such as flywheels or wheels. These parts must solve the inertial part by implementing the events GetState, SetSubstepState, GetSubstepDerivative and SetState additionally to the other events.
The Engine block is an example of inertial block.
Example: simple gear #
This code implements a simple gear block (SimpleGear) that constrains the input and output to corotate with the given ratio.
A custom vehicle controller using this SimpleGear block may look like this:
Check out Creating custom vehicles for a full implementation of a custom vehicle controller.
SimpleGear.cs
using VehiclePhysics;
public class SimpleGear : Block
{
public float ratio = 1.0f;
protected override void Initialize ()
{
// Declare this block to have a single input and a single output
SetInputs(1);
SetOutputs(1);
}
public override bool CheckConnections ()
{
// Both input and output are required to be connected to other blocks
return inputs[0] != null && outputs[0] != null;
}
public override void ComputeStateUpstream ()
{
// Take the state from the output connection, process it,
// and put the result at the input connection (upstream flow).
// L = angular momentum, I = inertia, Tr = reaction torque
inputs[0].L = output[0].L / ratio;
inputs[0].I = output[0].I / ratio / ratio;
inputs[0].Tr = output[0].Tr / ratio;
}
public override void EvaluateTorqueDownstream ()
{
// Take the torque from the input connection, process it,
// and put the result at the output connection (downstream flow).
outputs[0].outTd = inputs[0].outTd * ratio;
}
}
Example: simple differential #
Note: This differential implementation assumes the same inertia I
in both outputs. It won't
work if the outputs have different inertias. The Differential block in VPP
supports any inertias in its outputs.
The design of the modular driveline in VPP allows a straightforward translation of the state and torque formulas of an open differential for outputs of identical inertia:
SimpleOpenDifferential.cs
using VehiclePhysics;
public class SimpleOpenDifferential : Block
{
protected override void Initialize ()
{
// Declare this block to have a single input and a two outputs
SetInputs(1);
SetOutputs(2);
}
public override bool CheckConnections ()
{
// The input and both outputs are required to be connected to other blocks
return inputs[0] != null && outputs[0] != null && outputs[1] != null;
}
public override void ComputeStateUpstream ()
{
// The state of the input is the sum of the states of the outputs.
//
// NOTE: Inertias must be identical for this implementation to work. The calculation
// for different inertias is more complex (see the Differential block in VPP).
inputs[0].L = output[0].L + output[1].L;
inputs[0].I = output[0].I + output[1].I;
inputs[0].Tr = output[0].Tr + output[1].Tr;
}
public override void EvaluateTorqueDownstream ()
{
// An open differential splits the input torque 50-50 between both outputs
outputs[0].outTd = inputs[0].outTd * 0.5f;
outputs[1].outTd = inputs[0].outTd * 0.5f;
}
}