# Migrating From v0.1 to v0.2

## Take `SpatialQueryFilter` by reference in spatial queries

PRs: [#402](https://github.com/avianphysics/avian/pull/402)

Spatial queries performed through `SpatialQuery` now take `SpatialQueryFilter` by reference.

## Use hooks for component initialization

PRs: [#483](https://github.com/avianphysics/avian/pull/483)

`PrepareSet::PreInit` has been renamed to `PrepareSet::First`, and `PrepareSet::InitRigidBodies`, `PrepareSet::InitColliders`, and `PrepareSet::InitMassProperties` have been removed. Most missing components are now initialized by component lifecycle hooks.

`CcdPlugin` and `SpatialQueryPipeline` no longer store a schedule and are now unit structs. Instead of `SpatialQueryPlugin::new(my_schedule)` or `SpatialQueryPlugin::default()`, just use `SpatialQueryPlugin`.

## Use `FixedPostUpdate` by default and simplify scheduling

PRs: [#457](https://github.com/avianphysics/avian/pull/457)

Previously, physics was run in `PostUpdate` with a custom fixed timestep by default. The primary purpose of the fixed timestep is to make behavior consistent and frame rate independent.

This custom scheduling logic has been removed, and physics now runs in Bevy's `FixedPostUpdate` by default. This further unifies physics with Bevy's own APIs and simplifies scheduling. However, it also means that physics now runs before `Update`, unlike before.

For most users, no changes should be necessary, and systems that were running in `Update` can remain there. If you want to run systems at the same fixed timestep as physics, consider using `FixedUpdate`.

The `Time<Physics>` clock now automatically follows the clock used by the schedule that physics is run in. In `FixedPostUpdate` and other schedules with a fixed timestep, `Time<Fixed>` is used, but if physics is instead configured to run in a schedule with a variable timestep, like `PostUpdate`, it will use `Time<Virtual>`.

Previously, the physics timestep could be configured like this:

```rust
app.insert_resource(Time::new_with(Physics::fixed_hz(60.0)));
```

Now, if you are running physics in `FixedPostUpdate`, you should simply configure `Time<Fixed>` directly:

```rust
app.insert_resource(Time::<Fixed>::from_hz(60.0)));
```

The following types and methods have also been removed as a part of this rework:

- `TimestepMode`
- `Physics::from_timestep`
- `Physics::fixed_hz`
- `Physics::fixed_once_hz`
- `Physics::variable`
- `Time::<Physics>::from_timestep`
- `Time::<Physics>::timestep_mode`
- `Time::<Physics>::timestep_mode_mut`
- `Time::<Physics>::set_timestep_mode`

Previously, camera following logic had to be scheduled relative to both physics *and* transform propagation:

```rust
// Run after physics, before transform propagation.
app.add_systems(
    PostUpdate,
    camera_follow_player
        .after(PhysicsSet::Sync)
        .before(TransformSystem::TransformPropagate),
);
```

Since physics is now run in `FixedPostUpdate`, which is before `Update`, it is enough to order the system against just transform propagation:

```rust
// Note: camera following could technically be in `Update` too now.
app.add_systems(
    PostUpdate,
    camera_follow_player.before(TransformSystem::TransformPropagate),
);
```

## Use a single layer as the default membership instead of all

PRs: [#476](https://github.com/avianphysics/avian/pull/476), [#494](https://github.com/avianphysics/avian/pull/494)

Previously, `CollisionLayers` defaulted to "all memberships, all filters", meaning that everything belonged to every layer and could interact with every layer. This turned out to be very limiting in practice, as it made it impossible to target things like ray casts to specific layers, unless the memberships of all colliders were set explicitly.

Now, colliders only belong to the first layer by default. This means that the first bit `0b0001` in the layer mask is reserved for the default layer.

This also applies to enum-based layers using the `PhysicsLayer` derive macro. To make the default layer explicit, physics layer enums must now implement `Default`, and specify which variant represents the default layer `0b0001`.

```rust
#[derive(PhysicsLayer, Default)]
enum GameLayer {
    #[default]
    Default, // The name doesn't matter, but Default is used here for clarity
    Player,
    Enemy,
    Ground,
}
```

## Rework mass properties

PRs: [#500](https://github.com/avianphysics/avian/pull/500), [#532](https://github.com/avianphysics/avian/pull/532), [#574](https://github.com/avianphysics/avian/pull/574)

### Inverse Mass Components

- `InverseMass` and `InverseInertia` have been removed, and `Inertia` has been renamed to `AngularInertia`.
- `RigidBodyQueryItem` methods `effective_inv_mass` and `effective_world_inv_inertia` have been renamed to `effective_inverse_mass` and `effective_global_inverse_inertia`.

### `MassPropertyPlugin`

The `MassPropertyPlugin` is now needed to update mass properties automatically based on attached colliders. Most apps won't need to add it manually, as it is included in the `PhysicsPlugins` plugin group by default.

### Behavior Changes

- `Mass`, `AngularInertia`, and `CenterOfMass` are now optional, and can be used to override the mass properties of an entity if present, ignoring the entity's collider. Mass properties that are not set are still computed from the entity's `Collider` and `ColliderDensity`.
- Mass properties of child entities still contribute to the total mass properties of rigid bodies by default, but the total values are stored in `ComputedMass`, `ComputedAngularInertia`, and `ComputedCenterOfMass` instead of `Mass`, `AngularInertia`, and `CenterOfMass`. The latter components are now never modified by Avian directly.
- To prevent colliders or descendants from contributing to the total mass properties, add the `NoAutoMass`, `NoAutoAngularInertia`, and `NoAutoCenterOfMass` marker components to the rigid body, giving you full manual control.
- Previously, changing `Mass` at runtime did not affect angular inertia. Now, it is scaled accordingly, unless `NoAutoAngularInertia` is present.
- Previously, specifying the `CenterOfMass` at spawn did nothing *unless* an initial `Mass` was specified, even if the entity had a collider that would give it mass. This has been fixed.
- Previously, `Mass`, `AngularInertia`, and `CenterOfMass` did *nothing* on child colliders. Now, they effectively override `ColliderMassProperties` when computing the total mass properties for the rigid body.
- Previously, zero mass and angular inertia were treated as invalid. It emitted warnings, which was especially problematic and spammy for runtime collider constructors. Now, they are treated as acceptable values, and interpreted as infinite mass, like in most other engines.

### API Changes

- `Mass`, `AngularInertia`, `CenterOfMass`, `ColliderDensity`, and `ColliderMassProperties` now always use `f32` types, even with the `f64` feature. Total mass properties stored in `ComputedMass`, `ComputedAngularInertia`, and `ComputedCenterOfMass` still support `f64`.
- In 3D, `AngularInertia` now stores a principal angular inertia (`Vec3`) and the orientation of the local inertial frame (`Quat`) instead of an inertia tensor (`Mat3`). However, several different constructors are provided, including `from_tensor`.
- `MassPropertiesBundle::new_computed` and `ColliderMassProperties::from_collider` have been renamed to `from_shape`.
- `ColliderMassProperties` now stores a `MassProperties2d`/`MassProperties3d` instead of separate properties.
- Types implementing `AnyCollider` must now also implement the `ComputeMassProperties2d`/`ComputeMassProperties3d` trait instead of the `mass_properties` method.

## Collider Constructors

PRs: [#540](https://github.com/avianphysics/avian/pull/540)

`Collider::regular_polygon` and `ColliderConstructor::RegularPolygon` now use a `u32` instead of `usize` for `sides`.

## Use required components for component initialization

PRs: [#541](https://github.com/avianphysics/avian/pull/541)

The `CollidingEntities` component is no longer added automatically. To read entities that are colliding with a given entity, you must now add the `CollidingEntities` component for it manually.

To revert to the old behavior, you can also make `CollidingEntities` a required component for colliders:

```rust
app.register_required_components::<Collider, CollidingEntities>();
```

## Improvements to friction and restitution

PRs: [#551](https://github.com/avianphysics/avian/pull/551)

`Friction` and `Restitution` are no longer inserted automatically for rigid bodies. Instead, there are now `DefaultFriction` and `DefaultRestitution` resources, which are used for bodies with no `Friction` or `Restitution` specified. These resources can be configured to change the global defaults for friction and restitution.

The default restitution is now `0.0`, meaning that bodies are no longer bouncy by default. The default coefficients of friction have also been increased from `0.3` to `0.5`.

## Add `SolverSchedulePlugin` to encapsulate solver scheduling

PRs: [#577](https://github.com/avianphysics/avian/pull/577)

System set configuration and scheduling related to the solver and substepping loop are now primarily in the new `SolverSchedulePlugin`. It is included in the `PhysicsPlugins` plugin group, so for most applications, this should not be a breaking change.

## Improve `SpatialQuery` APIs and docs, and add more configuration

PRs: [#510](https://github.com/avianphysics/avian/pull/510)

### Shape Casting Configuration

`SpatialQuery` methods like `cast_shape` and `shape_hits` now take a `ShapeCastConfig`, which contains a lot of the existing configuration options, along with a few new options.

```rust
// Before
let hits = spatial.shape_hits(
    &Collider::sphere(0.5),
    Vec3::ZERO,
    Quat::default(),
    Dir3::ZERO,
    100.0,
    10,
    false,
    &SpatialQueryFilter::from_mask(LayerMask::ALL),
);

// After
let hits = spatial.shape_hits(
    &Collider::sphere(0.5),
    Vec3::ZERO,
    Quat::default(),
    Dir3::ZERO,
    10,
    &ShapeCastConfig::from_max_distance(100.0),
    &SpatialQueryFilter::from_mask(LayerMask::ALL),
);
```

### Time of Impact → Distance

Spatial query APIs that mention the "time of impact" have been changed to refer to "distance". This affects names of properties and methods, such as:

- `RayCaster::max_time_of_impact` → `RayCaster::max_distance`
- `RayCaster::with_max_time_of_impact` → `RayCaster::with_max_distance`
- `ShapeCaster::max_time_of_impact` → `ShapeCaster::max_distance`
- `ShapeCaster::with_max_time_of_impact` → `ShapeCaster::with_max_distance`
- `RayHitData::time_of_impact` → `RayHitData::distance`
- `ShapeHitData::time_of_impact` → `ShapeHitData::distance`
- `max_time_of_impact` on `SpatialQuery` methods → `RayCastConfig::max_distance` or `ShapeCastConfig::max_distance`

This was changed because "distance" is clearer than "time of impact" for many users, and it is still an accurate term, as the cast directions in Avian are always normalized, so the "velocity" is of unit length.
