PRs: #815
Avian 0.4 migrates Avian to Bevy 0.17. This involves some breaking changes.
The CollisionStarted, CollisionEnded, OnCollisionStart, and OnCollisionEnd events have been replaced by the CollisionStart and CollisionEnd events. They are both written as a Message and triggered as an Event, and store the collider and body entity of both colliders involved in the event.
A collision event observer before:
fn on_player_stepped_on_plate(event: Trigger<OnCollisionStart>, player_query: Query<&Player>) {
let pressure_plate = event.target();
let other_entity = event.collider;
if player_query.contains(other_entity) {
println!("Player {other_entity} stepped on pressure plate {pressure_plate}");
}
}and after:
fn on_player_stepped_on_plate(event: On<CollisionStart>, player_query: Query<&Player>) {
let pressure_plate = event.collider1;
let other_entity = event.collider2;
if player_query.contains(other_entity) {
println!("Player {other_entity} stepped on pressure plate {pressure_plate}");
}
}A collision event reader system before:
fn print_started_collisions(mut collision_reader: EventReader<CollisionStarted>) {
for CollisionStarted(collider1, collider2) in collision_reader.read() {
println!("{collider1} and {collider2} started colliding");
}
}and after:
fn print_started_collisions(mut collision_reader: MessageReader<CollisionStart>) {
// Note: The event now also stores `body1` and `body2`
for event in collision_reader.read() {
println!("{} and {} started colliding", event.collider1, event.collider2);
}
}System sets have been renamed to follow the new FooSystems naming convention.
PhysicsSet→PhysicsSystemsPhysicsStepSet→PhysicsStepSystemsSubstepSet→SubstepSystemsSubstepSolverSet→SubstepSolverSystemsSolverSet→SolverSystemsIntegrationSet→IntegrationSystemsBroadPhaseSet→BroadPhaseSystemsNarrowPhaseSet→NarrowPhaseSystemsSweptCcdSet→SweptCcdSystemsPhysicsTransformSet→PhysicsTransformSystems
Bevy 0.17 changed the way Name works for glTF mesh primitives (migration guide). Instead of MeshName.PrimitiveIndex, it is now in the form of MeshName.MaterialName. This also means that APIs such as ColliderConstructorHierarchy::with_constructor_for_name now use this format.
ColliderConstructorHierarchy::new(ColliderConstructor::ConvexDecompositionFromMesh)
.with_density_for_name("armL_mesh.ferris_material", 3.0)
.with_density_for_name("armR_mesh.ferris_material", 3.0)PRs: #770
Avian 0.4 overhauls the force APIs, and removes the ExternalForce, ExternalTorque, ExternalImpulse, and ExternalAngularImpulse components.
- For persistent forces and torques, use the new
ConstantForceandConstantTorquecomponents. - For non-persistent forces that get cleared automatically, use the new
ForceshelperQueryData. - Impulses can no longer be persistent. Use persistent forces instead.
The new ForcePlugin must be enabled for forces to function properly. It is included in PhysicsPlugins by default.
Avian 0.4 contains a lot of changes and improvements for joints.
- Joint APIs are now in
dynamics::jointsinstead ofdynamics::solver::joints - The
Jointtrait has been removed in favor of theEntityConstrainttrait and helper methods on the joint types themselves - Renamed
entity1andentity2tobody1andbody2 - Renamed
free_axistoslider_axisforPrismaticJoint - Renamed
aligned_axistohinge_axisforRevoluteJoint - Renamed
with_local_anchor_1,with_local_anchor_2,local_anchor_1, andlocal_anchor_2towith_local_anchor1,with_local_anchor2,local_anchor1, andlocal_anchor2 - The
local_anchor1andlocal_anchor2methods now return anOption - The
FixedJoint,PrismaticJoint,RevoluteJoint, andSphericalJointnow store a fullJointFrame(anchor + basis) for each body instead of just local anchors - Removed
swing_axisfromSphericalJoint; just set thetwist_axis, and the swing limit cone will be oriented accordingly - Removed damping properties and methods from joint types in favor of the
JointDampingcomponent - Removed force properties and methods from joint types in favor of the
JointForcescomponent - Each part of a joint has its own compliance and helpers for it, such as
with_point_complianceandwith_swing_compliance.
Entities can now only hold up to one type of joint component. If a joint is added on an entity that already has a joint, the old joint is automatically removed, and a warning is emitted if debug_assertions are enabled. A rigid body can still be attached to other bodies by multiple joints, but each joint must be on its own entity.
ContactEdge now also stores the rigid body entities.
The rest_length property of DistanceJoint has been removed in favor of just using length_limits.
- Replace
DistanceJoint::with_rest_length(1.0)withDistanceJoint::with_limits(1.0, 1.0). - Replace
joint.rest_length = 1.0withjoint.length_limits = 1.0.into().
- XPBD logic is now contained within
dynamics::solver::xpbd, gated behind thexpbd_jointsfeature - XPBD system sets from
SubstepSolverSethave been extracted to a separateXpbdSolverSystemsenum - XPBD systems are now initialized by an
XpbdSolverPlugin
- The
XpbdConstrainttrait now has apreparestep to prepare base translational and rotational offsets and any other pre-step data. XpbdConstraintnow has aSolverDataassociated type for a solver data component implementing theXpbdConstraintSolverDatatrait. This is taken byprepareandsolve.XpbdConstraint::solveand many related methods now useSolverBodyandSolverBodyInertiastructs. Positional corrections are applied to thedelta_positionanddelta_rotationproperties. Updated positional information can be computed based on the pre-step data and these deltas.apply_positional_lagrange_updatehas been removed. Useapply_positional_impulseinstead.xpbd::solve_constraintis nowxpbd::solve_xpbd_joint, and only supports two entities (make your own system if you need more).- Most methods that previously returned forces or torques now return Lagrange multiplier updates.
- See the
custom_constraintexample for a functional demonstration of implementing a custom constraint.
ContactPoint::normal_impulse previously corresponded to the clamped accumulated normal impulse from the last substep, used for warm starting the contact solver. It did not represent the total impulse applied across substeps and restitution, despite the ambiguous name.
Now, ContactPoint::normal_impulse works like you would expect, and represents the total normal impulse applied at a contact point. Divide by the time step to get the corresponding force.
The old warm starting impulses are now stored as warm_start_normal_impulse and warm_start_tangent_impulse (previously tangent_impulse).
The method APIs such as total_normal_impulse, total_normal_impulse_magnitude, and max_normal_impulse have been updated accordingly to use the new normal_impulse. Additionally, ContactPair::max_normal_impulse has been split into ContactPair::max_normal_impulse (returns a vector) and ContactPair::max_normal_impulse_magnitude (returns a scalar).
The normal_force and tangent_force methods of ContactPoint have been removed.
ContactConstraintPoint::max_normal_impulse is now stored in the ContactNormalPart as total_impulse.
The local_point1 and local_point2 properties of ContactPoint have been removed in favor of a world-space anchor1 and anchor2 relative to the center of mass.
The global_point1 and global_point2 methods have also been removed, but a new world-space point is available for the midpoint between the closest points.
- The
ContactGraphnow storesContactEdges in the graph, containing only edge connectivity information with stableContactIds. - The
ContactGraphnow storesContactPairs in separateactive_pairsandsleeping_pairslists. iteranditer_muthave been renamed toiter_activeanditer_active_mut/iter_sleepinganditer_sleeping_mut.iter_touchinganditer_touching_muthave been renamed toiter_touching_activeanditer_touching_active_mut/iter_touching_sleepinganditer_touching_sleeping_mut.collisions_withhas been renamed tocontact_pairs_with.collisions_with_muthas been removed for now.add_pairhas been replaced byadd_edge, andadd_pair_with_keyhas been replaced byadd_edge_and_key_with.insert_pairandinsert_pair_withhave been removed. Add or update pairs manually instead.remove_pairhas been renamed toremove_edge.
ContactPairnow stores theContactIdassociated with theContactEdgein theContactGraph. It must be provided toContactPair::new. It is initialized automatically by calls to methods likeContactGraph::add_edge.ContactPairFlagsno longer stores whetherCONTACT_EVENTSare enabled. It is instead stored onContactEdgeFlags.ContactManifoldno longer stores theindexof the manifold.
PRs: #809
Stacks of bodies as well as bodies connected by joints now form "simulation islands" that are allowed to enter a low-cost sleeping state when all bodies in a given island are resting. This can significantly reduce CPU overhead for large game worlds with lots of dynamic bodies. Previously, bodies were only allowed to sleep when they were not interacting with other dynamic bodies.
The following components have been renamed:
TimeSleeping->SleepTimerSleepingThreshold->SleepThresholdDeactivationTime->TimeToSleep(also a component and not a resource now)
Additionally, the SleepingPlugin has been replaced by the IslandSleepingPlugin.
PRs: #735
Avian's solver now uses special SolverBody and SolverBodyInertia components instead of separate components like Position, Rotation, AccumulatedTranslation, LinearVelocity, and AngularVelocity. They are initialized for awake dynamic and kinematic bodies in the substepping loop, and the results are written back to the user-facing components at the end. This also means that if you are running custom logic inside the substepping loop, you should generally use SolverBody instead of the separate components.
Solver bodies were added to drastically improve the performance of the solver, but it also means significant changes to internals.
The following components have been removed and are no longer stored for rigid bodies:
AccumulatedTranslationPreSolveAccumulatedTranslation(now calledPreSolveDeltaPosition)PreSolveLinearVelocityPreSolveAngularVelocityPreSolveRotationPreviousRotation
A new PreSolveDeltaRotation component has also been added.
The current_position helper on RigidBodyQueryItem and ColliderQueryItem has been removed.
The local_anchor1 and local_anchor2 properties on ContactConstraintPoint have been removed.
SolverSet::ApplyTranslationhas been renamed toSolverSystems::Finalize.
Position,Rotation, andColliderAabbare now initialized with correct world-space values right after spawn.- The
SyncPluginhas been renamed toPhysicsTransformPlugin, andSyncSethas been renamed toPhysicsTransformSystems. - The
PreparePluginandPrepareSethave been removed. UsePhysicsSet::Preparefor preparation logic, and run it afterPhysicsTransformSystems::TransformToPositionif it must run after transforms have been applied to physics positions. - Logic inside the
PhysicsSchedulecan no longer useTransform. UsePositionandRotationinstead. PhysicsSet::Synchas been renamed toPhysicsSet::Writeback.SyncConfighas been renamed toPhysicsTransformConfig.
PRs: #777
In 3D, AngularInertia and ComputedAngularInertia APIs now use a SymmetricMat3 from glam_natrix_extras instead of the old Mat3 for the angular inertia tensor. AngularInertia has new constructors like try_from_mat3 and from_mat3_unchecked to use Mat3 directly.
The GlobalAngularInertia component has been removed. You can compute the rotated angular inertia tensor using ComputedAngularInertia::rotated.
PRs: #829
The PhysicsDebugPlugin now always runs in PostUpdate. Replace calls to PhysicsDebugPlugin::new(SomeSchedule) with PhysicsDebugPlugin or PhysicsDebugPlugin::default().
Additionally, debug rendering now uses GlobalTransform instead of Position and Rotation. This allows debug rendering to use interpolated transforms if TransformInterpolation is used.
PRs: #761
Collider::trimesh and Collider::trimesh_with_config can now panic for degenerate input. Use Collider::try_trimesh and Collider::try_trimesh_with_config to instead get a Result and handle error cases manually.
PRs: #775
The ColliderQuery QueryData type no longer exists. Query for the components you need manually, or define your own QueryData type.