Allow disabling colliders, rigid-bodies and impulse joints
This commit is contained in:
@@ -133,7 +133,7 @@ impl Default for KinematicCharacterController {
|
|||||||
pub struct EffectiveCharacterMovement {
|
pub struct EffectiveCharacterMovement {
|
||||||
/// The movement to apply.
|
/// The movement to apply.
|
||||||
pub translation: Vector<Real>,
|
pub translation: Vector<Real>,
|
||||||
/// Is the character touching the ground after applying `EffictiveKineamticMovement::translation`?
|
/// Is the character touching the ground after applying `EffectiveKineamticMovement::translation`?
|
||||||
pub grounded: bool,
|
pub grounded: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,8 @@ impl IslandManager {
|
|||||||
let rb = bodies.index_mut_internal(handle);
|
let rb = bodies.index_mut_internal(handle);
|
||||||
rb.activation.wake_up(strong);
|
rb.activation.wake_up(strong);
|
||||||
|
|
||||||
if self.active_dynamic_set.get(rb.ids.active_set_id) != Some(&handle) {
|
if rb.is_enabled() && self.active_dynamic_set.get(rb.ids.active_set_id) != Some(&handle)
|
||||||
|
{
|
||||||
rb.ids.active_set_id = self.active_dynamic_set.len();
|
rb.ids.active_set_id = self.active_dynamic_set.len();
|
||||||
self.active_dynamic_set.push(handle);
|
self.active_dynamic_set.push(handle);
|
||||||
}
|
}
|
||||||
@@ -256,12 +257,12 @@ impl IslandManager {
|
|||||||
// in contact or joined with this collider.
|
// in contact or joined with this collider.
|
||||||
push_contacting_bodies(&rb.colliders, colliders, narrow_phase, &mut self.stack);
|
push_contacting_bodies(&rb.colliders, colliders, narrow_phase, &mut self.stack);
|
||||||
|
|
||||||
for inter in impulse_joints.attached_joints(handle) {
|
for inter in impulse_joints.attached_enabled_joints(handle) {
|
||||||
let other = crate::utils::select_other((inter.0, inter.1), handle);
|
let other = crate::utils::select_other((inter.0, inter.1), handle);
|
||||||
self.stack.push(other);
|
self.stack.push(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
for other in multibody_joints.attached_bodies(handle) {
|
for other in multibody_joints.bodies_attached_with_enabled_joint(handle) {
|
||||||
self.stack.push(other);
|
self.stack.push(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crate::utils::{WBasis, WReal};
|
|||||||
|
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
use crate::dynamics::SphericalJoint;
|
use crate::dynamics::SphericalJoint;
|
||||||
|
use crate::geometry::ColliderEnabled;
|
||||||
|
|
||||||
#[cfg(feature = "dim3")]
|
#[cfg(feature = "dim3")]
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
@@ -182,6 +183,19 @@ impl JointMotor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||||
|
/// Enum indicating whether or not a joint is enabled.
|
||||||
|
pub enum JointEnabled {
|
||||||
|
/// The joint is enabled.
|
||||||
|
Enabled,
|
||||||
|
/// The joint wasn’t disabled by the user explicitly but it is attached to
|
||||||
|
/// a disabled rigid-body.
|
||||||
|
DisabledByAttachedBody,
|
||||||
|
/// The joint is disabled by the user explicitly.
|
||||||
|
Disabled,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
/// A generic joint.
|
/// A generic joint.
|
||||||
@@ -208,6 +222,8 @@ pub struct GenericJoint {
|
|||||||
pub motors: [JointMotor; SPATIAL_DIM],
|
pub motors: [JointMotor; SPATIAL_DIM],
|
||||||
/// Are contacts between the attached rigid-bodies enabled?
|
/// Are contacts between the attached rigid-bodies enabled?
|
||||||
pub contacts_enabled: bool,
|
pub contacts_enabled: bool,
|
||||||
|
/// Whether or not the joint is enabled.
|
||||||
|
pub enabled: JointEnabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GenericJoint {
|
impl Default for GenericJoint {
|
||||||
@@ -222,6 +238,7 @@ impl Default for GenericJoint {
|
|||||||
limits: [JointLimits::default(); SPATIAL_DIM],
|
limits: [JointLimits::default(); SPATIAL_DIM],
|
||||||
motors: [JointMotor::default(); SPATIAL_DIM],
|
motors: [JointMotor::default(); SPATIAL_DIM],
|
||||||
contacts_enabled: true,
|
contacts_enabled: true,
|
||||||
|
enabled: JointEnabled::Enabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -260,6 +277,27 @@ impl GenericJoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is this joint enabled?
|
||||||
|
pub fn is_enabled(&self) -> bool {
|
||||||
|
self.enabled == JointEnabled::Enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set whether this joint is enabled or not.
|
||||||
|
pub fn set_enabled(&mut self, enabled: bool) {
|
||||||
|
match self.enabled {
|
||||||
|
JointEnabled::Enabled | JointEnabled::DisabledByAttachedBody => {
|
||||||
|
if !enabled {
|
||||||
|
self.enabled = JointEnabled::Disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JointEnabled::Disabled => {
|
||||||
|
if enabled {
|
||||||
|
self.enabled = JointEnabled::Enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Add the specified axes to the set of axes locked by this joint.
|
/// Add the specified axes to the set of axes locked by this joint.
|
||||||
pub fn lock_axes(&mut self, axes: JointAxesMask) -> &mut Self {
|
pub fn lock_axes(&mut self, axes: JointAxesMask) -> &mut Self {
|
||||||
self.locked_axes |= axes;
|
self.locked_axes |= axes;
|
||||||
|
|||||||
@@ -72,11 +72,11 @@ impl ImpulseJointSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates through all the joints between two rigid-bodies.
|
/// Iterates through all the joints between two rigid-bodies.
|
||||||
pub fn joints_between<'a>(
|
pub fn joints_between(
|
||||||
&'a self,
|
&self,
|
||||||
body1: RigidBodyHandle,
|
body1: RigidBodyHandle,
|
||||||
body2: RigidBodyHandle,
|
body2: RigidBodyHandle,
|
||||||
) -> impl Iterator<Item = (ImpulseJointHandle, &'a ImpulseJoint)> {
|
) -> impl Iterator<Item = (ImpulseJointHandle, &ImpulseJoint)> {
|
||||||
self.rb_graph_ids
|
self.rb_graph_ids
|
||||||
.get(body1.0)
|
.get(body1.0)
|
||||||
.zip(self.rb_graph_ids.get(body2.0))
|
.zip(self.rb_graph_ids.get(body2.0))
|
||||||
@@ -86,15 +86,15 @@ impl ImpulseJointSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates through all the impulse joints attached to the given rigid-body.
|
/// Iterates through all the impulse joints attached to the given rigid-body.
|
||||||
pub fn attached_joints<'a>(
|
pub fn attached_joints(
|
||||||
&'a self,
|
&self,
|
||||||
body: RigidBodyHandle,
|
body: RigidBodyHandle,
|
||||||
) -> impl Iterator<
|
) -> impl Iterator<
|
||||||
Item = (
|
Item = (
|
||||||
RigidBodyHandle,
|
RigidBodyHandle,
|
||||||
RigidBodyHandle,
|
RigidBodyHandle,
|
||||||
ImpulseJointHandle,
|
ImpulseJointHandle,
|
||||||
&'a ImpulseJoint,
|
&ImpulseJoint,
|
||||||
),
|
),
|
||||||
> {
|
> {
|
||||||
self.rb_graph_ids
|
self.rb_graph_ids
|
||||||
@@ -104,6 +104,35 @@ impl ImpulseJointSet {
|
|||||||
.map(|inter| (inter.0, inter.1, inter.2.handle, inter.2))
|
.map(|inter| (inter.0, inter.1, inter.2.handle, inter.2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterates through all the impulse joints attached to the given rigid-body.
|
||||||
|
pub fn map_attached_joints_mut<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
body: RigidBodyHandle,
|
||||||
|
mut f: impl FnMut(RigidBodyHandle, RigidBodyHandle, ImpulseJointHandle, &mut ImpulseJoint),
|
||||||
|
) {
|
||||||
|
self.rb_graph_ids.get(body.0).into_iter().for_each(|id| {
|
||||||
|
for inter in self.joint_graph.interactions_with_mut(*id) {
|
||||||
|
(f)(inter.0, inter.1, inter.3.handle, inter.3)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterates through all the enabled impulse joints attached to the given rigid-body.
|
||||||
|
pub fn attached_enabled_joints(
|
||||||
|
&self,
|
||||||
|
body: RigidBodyHandle,
|
||||||
|
) -> impl Iterator<
|
||||||
|
Item = (
|
||||||
|
RigidBodyHandle,
|
||||||
|
RigidBodyHandle,
|
||||||
|
ImpulseJointHandle,
|
||||||
|
&ImpulseJoint,
|
||||||
|
),
|
||||||
|
> {
|
||||||
|
self.attached_joints(body)
|
||||||
|
.filter(|inter| inter.3.data.is_enabled())
|
||||||
|
}
|
||||||
|
|
||||||
/// Is the given joint handle valid?
|
/// Is the given joint handle valid?
|
||||||
pub fn contains(&self, handle: ImpulseJointHandle) -> bool {
|
pub fn contains(&self, handle: ImpulseJointHandle) -> bool {
|
||||||
self.joint_ids.contains(handle.0)
|
self.joint_ids.contains(handle.0)
|
||||||
@@ -246,7 +275,7 @@ impl ImpulseJointSet {
|
|||||||
ImpulseJointHandle(handle)
|
ImpulseJointHandle(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve all the impulse_joints happening between two active bodies.
|
/// Retrieve all the enabled impulse joints happening between two active bodies.
|
||||||
// NOTE: this is very similar to the code from NarrowPhase::select_active_interactions.
|
// NOTE: this is very similar to the code from NarrowPhase::select_active_interactions.
|
||||||
pub(crate) fn select_active_interactions(
|
pub(crate) fn select_active_interactions(
|
||||||
&self,
|
&self,
|
||||||
@@ -264,7 +293,8 @@ impl ImpulseJointSet {
|
|||||||
let rb1 = &bodies[joint.body1];
|
let rb1 = &bodies[joint.body1];
|
||||||
let rb2 = &bodies[joint.body2];
|
let rb2 = &bodies[joint.body2];
|
||||||
|
|
||||||
if (rb1.is_dynamic() || rb2.is_dynamic())
|
if joint.data.is_enabled()
|
||||||
|
&& (rb1.is_dynamic() || rb2.is_dynamic())
|
||||||
&& (!rb1.is_dynamic() || !rb1.is_sleeping())
|
&& (!rb1.is_dynamic() || !rb1.is_sleeping())
|
||||||
&& (!rb2.is_dynamic() || !rb2.is_sleeping())
|
&& (!rb2.is_dynamic() || !rb2.is_sleeping())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ impl MultibodyJointSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate through the handles of all the rigid-bodies attached to this rigid-body
|
/// Iterate through the handles of all the rigid-bodies attached to this rigid-body
|
||||||
/// by an multibody_joint.
|
/// by a multibody_joint.
|
||||||
pub fn attached_bodies<'a>(
|
pub fn attached_bodies<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
body: RigidBodyHandle,
|
body: RigidBodyHandle,
|
||||||
@@ -384,6 +384,21 @@ impl MultibodyJointSet {
|
|||||||
.map(move |inter| crate::utils::select_other((inter.0, inter.1), body))
|
.map(move |inter| crate::utils::select_other((inter.0, inter.1), body))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterate through the handles of all the rigid-bodies attached to this rigid-body
|
||||||
|
/// by an enabled multibody_joint.
|
||||||
|
pub fn bodies_attached_with_enabled_joint<'a>(
|
||||||
|
&'a self,
|
||||||
|
body: RigidBodyHandle,
|
||||||
|
) -> impl Iterator<Item = RigidBodyHandle> + 'a {
|
||||||
|
self.attached_bodies(body).filter(move |other| {
|
||||||
|
if let Some((_, _, link)) = self.joint_between(body, *other) {
|
||||||
|
link.joint.data.is_enabled()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Iterates through all the multibodies on this set.
|
/// Iterates through all the multibodies on this set.
|
||||||
pub fn multibodies(&self) -> impl Iterator<Item = &Multibody> {
|
pub fn multibodies(&self) -> impl Iterator<Item = &Multibody> {
|
||||||
self.multibodies.iter().map(|e| e.1)
|
self.multibodies.iter().map(|e| e.1)
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ pub struct RigidBody {
|
|||||||
pub(crate) body_type: RigidBodyType,
|
pub(crate) body_type: RigidBodyType,
|
||||||
/// The dominance group this rigid-body is part of.
|
/// The dominance group this rigid-body is part of.
|
||||||
pub(crate) dominance: RigidBodyDominance,
|
pub(crate) dominance: RigidBodyDominance,
|
||||||
|
pub(crate) enabled: bool,
|
||||||
/// User-defined data associated to this rigid-body.
|
/// User-defined data associated to this rigid-body.
|
||||||
pub user_data: u128,
|
pub user_data: u128,
|
||||||
}
|
}
|
||||||
@@ -61,6 +62,7 @@ impl RigidBody {
|
|||||||
changes: RigidBodyChanges::all(),
|
changes: RigidBodyChanges::all(),
|
||||||
body_type: RigidBodyType::Dynamic,
|
body_type: RigidBodyType::Dynamic,
|
||||||
dominance: RigidBodyDominance::default(),
|
dominance: RigidBodyDominance::default(),
|
||||||
|
enabled: true,
|
||||||
user_data: 0,
|
user_data: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,6 +83,28 @@ impl RigidBody {
|
|||||||
&mut self.activation
|
&mut self.activation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is this rigid-body enabled?
|
||||||
|
pub fn is_enabled(&self) -> bool {
|
||||||
|
self.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets whether this rigid-body is enabled or not.
|
||||||
|
pub fn set_enabled(&mut self, enabled: bool) {
|
||||||
|
if enabled != self.enabled {
|
||||||
|
if enabled {
|
||||||
|
// NOTE: this is probably overkill, but it makes sure we don’t
|
||||||
|
// forget anything that needs to be updated because the rigid-body
|
||||||
|
// was basically interpreted as if it was removed while it was
|
||||||
|
// disabled.
|
||||||
|
self.changes = RigidBodyChanges::all();
|
||||||
|
} else {
|
||||||
|
self.changes |= RigidBodyChanges::ENABLED_OR_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.enabled = enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The linear damping coefficient of this rigid-body.
|
/// The linear damping coefficient of this rigid-body.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn linear_damping(&self) -> Real {
|
pub fn linear_damping(&self) -> Real {
|
||||||
@@ -963,6 +987,8 @@ pub struct RigidBodyBuilder {
|
|||||||
pub ccd_enabled: bool,
|
pub ccd_enabled: bool,
|
||||||
/// The dominance group of the rigid-body to be built.
|
/// The dominance group of the rigid-body to be built.
|
||||||
pub dominance_group: i8,
|
pub dominance_group: i8,
|
||||||
|
/// Will the rigid-body being built be enabled?
|
||||||
|
pub enabled: bool,
|
||||||
/// An arbitrary user-defined 128-bit integer associated to the rigid-bodies built by this builder.
|
/// An arbitrary user-defined 128-bit integer associated to the rigid-bodies built by this builder.
|
||||||
pub user_data: u128,
|
pub user_data: u128,
|
||||||
}
|
}
|
||||||
@@ -984,6 +1010,7 @@ impl RigidBodyBuilder {
|
|||||||
sleeping: false,
|
sleeping: false,
|
||||||
ccd_enabled: false,
|
ccd_enabled: false,
|
||||||
dominance_group: 0,
|
dominance_group: 0,
|
||||||
|
enabled: true,
|
||||||
user_data: 0,
|
user_data: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1230,6 +1257,12 @@ impl RigidBodyBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable or disable the rigid-body after its creation.
|
||||||
|
pub fn enabled(mut self, enabled: bool) -> Self {
|
||||||
|
self.enabled = enabled;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Build a new rigid-body with the parameters configured with this builder.
|
/// Build a new rigid-body with the parameters configured with this builder.
|
||||||
pub fn build(&self) -> RigidBody {
|
pub fn build(&self) -> RigidBody {
|
||||||
let mut rb = RigidBody::new();
|
let mut rb = RigidBody::new();
|
||||||
@@ -1252,6 +1285,7 @@ impl RigidBodyBuilder {
|
|||||||
rb.damping.angular_damping = self.angular_damping;
|
rb.damping.angular_damping = self.angular_damping;
|
||||||
rb.forces.gravity_scale = self.gravity_scale;
|
rb.forces.gravity_scale = self.gravity_scale;
|
||||||
rb.dominance = RigidBodyDominance(self.dominance_group);
|
rb.dominance = RigidBodyDominance(self.dominance_group);
|
||||||
|
rb.enabled = self.enabled;
|
||||||
rb.enable_ccd(self.ccd_enabled);
|
rb.enable_ccd(self.ccd_enabled);
|
||||||
|
|
||||||
if self.can_sleep && self.sleeping {
|
if self.can_sleep && self.sleeping {
|
||||||
|
|||||||
@@ -112,6 +112,8 @@ bitflags::bitflags! {
|
|||||||
const DOMINANCE = 1 << 5;
|
const DOMINANCE = 1 << 5;
|
||||||
/// Flag indicating that the local mass-properties of this rigid-body must be recomputed.
|
/// Flag indicating that the local mass-properties of this rigid-body must be recomputed.
|
||||||
const LOCAL_MASS_PROPERTIES = 1 << 6;
|
const LOCAL_MASS_PROPERTIES = 1 << 6;
|
||||||
|
/// Flag indicating that the rigid-body was enabled or disabled.
|
||||||
|
const ENABLED_OR_DISABLED = 1 << 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,12 +331,14 @@ impl RigidBodyMassProps {
|
|||||||
|
|
||||||
for handle in &attached_colliders.0 {
|
for handle in &attached_colliders.0 {
|
||||||
if let Some(co) = colliders.get(*handle) {
|
if let Some(co) = colliders.get(*handle) {
|
||||||
if let Some(co_parent) = co.parent {
|
if co.is_enabled() {
|
||||||
let to_add = co
|
if let Some(co_parent) = co.parent {
|
||||||
.mprops
|
let to_add = co
|
||||||
.mass_properties(&*co.shape)
|
.mprops
|
||||||
.transform_by(&co_parent.pos_wrt_parent);
|
.mass_properties(&*co.shape)
|
||||||
self.local_mprops += to_add;
|
.transform_by(&co_parent.pos_wrt_parent);
|
||||||
|
self.local_mprops += to_add;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,11 @@ impl BroadPhase {
|
|||||||
/// This method will actually remove from the proxy list all the proxies
|
/// This method will actually remove from the proxy list all the proxies
|
||||||
/// marked as deletable by `self.predelete_proxy`, making their proxy
|
/// marked as deletable by `self.predelete_proxy`, making their proxy
|
||||||
/// handles re-usable by new proxies.
|
/// handles re-usable by new proxies.
|
||||||
fn complete_removals(&mut self, removed_colliders: &[ColliderHandle]) {
|
fn complete_removals(
|
||||||
|
&mut self,
|
||||||
|
colliders: &mut ColliderSet,
|
||||||
|
removed_colliders: &[ColliderHandle],
|
||||||
|
) {
|
||||||
// If there is no layer, there is nothing to remove.
|
// If there is no layer, there is nothing to remove.
|
||||||
if self.layers.is_empty() {
|
if self.layers.is_empty() {
|
||||||
return;
|
return;
|
||||||
@@ -224,6 +228,11 @@ impl BroadPhase {
|
|||||||
self.proxies.remove(proxy_id);
|
self.proxies.remove(proxy_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(co) = colliders.get_mut_internal(*removed) {
|
||||||
|
// Reset the proxy index.
|
||||||
|
co.bf_data.proxy_index = crate::INVALID_U32;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,9 +469,10 @@ impl BroadPhase {
|
|||||||
// NOTE: we use `get` because the collider may no longer
|
// NOTE: we use `get` because the collider may no longer
|
||||||
// exist if it has been removed.
|
// exist if it has been removed.
|
||||||
if let Some(co) = colliders.get_mut_internal(*handle) {
|
if let Some(co) = colliders.get_mut_internal(*handle) {
|
||||||
if !co.changes.needs_broad_phase_update() {
|
if !co.is_enabled() || !co.changes.needs_broad_phase_update() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_proxy_id = co.bf_data.proxy_index;
|
let mut new_proxy_id = co.bf_data.proxy_index;
|
||||||
|
|
||||||
if self.handle_modified_collider(
|
if self.handle_modified_collider(
|
||||||
@@ -496,7 +506,7 @@ impl BroadPhase {
|
|||||||
|
|
||||||
// Phase 5: bottom-up pass to remove proxies, and propagate region removed from smaller
|
// Phase 5: bottom-up pass to remove proxies, and propagate region removed from smaller
|
||||||
// layers to possible remove regions from larger layers that would become empty that way.
|
// layers to possible remove regions from larger layers that would become empty that way.
|
||||||
self.complete_removals(removed_colliders);
|
self.complete_removals(colliders, removed_colliders);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Propagate regions from the smallest layers up to the larger layers.
|
/// Propagate regions from the smallest layers up to the larger layers.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use crate::geometry::{
|
|||||||
use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector, DIM};
|
use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector, DIM};
|
||||||
use crate::parry::transformation::vhacd::VHACDParameters;
|
use crate::parry::transformation::vhacd::VHACDParameters;
|
||||||
use crate::pipeline::{ActiveEvents, ActiveHooks};
|
use crate::pipeline::{ActiveEvents, ActiveHooks};
|
||||||
|
use crate::prelude::ColliderEnabled;
|
||||||
use na::Unit;
|
use na::Unit;
|
||||||
use parry::bounding_volume::Aabb;
|
use parry::bounding_volume::Aabb;
|
||||||
use parry::shape::{Shape, TriMeshFlags};
|
use parry::shape::{Shape, TriMeshFlags};
|
||||||
@@ -154,6 +155,32 @@ impl Collider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is this collider enabled?
|
||||||
|
pub fn is_enabled(&self) -> bool {
|
||||||
|
match self.flags.enabled {
|
||||||
|
ColliderEnabled::Enabled => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets whether or not this collider is enabled.
|
||||||
|
pub fn set_enabled(&mut self, enabled: bool) {
|
||||||
|
match self.flags.enabled {
|
||||||
|
ColliderEnabled::Enabled | ColliderEnabled::DisabledByParent => {
|
||||||
|
if !enabled {
|
||||||
|
self.changes.insert(ColliderChanges::ENABLED_OR_DISABLED);
|
||||||
|
self.flags.enabled = ColliderEnabled::Disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ColliderEnabled::Disabled => {
|
||||||
|
if enabled {
|
||||||
|
self.changes.insert(ColliderChanges::ENABLED_OR_DISABLED);
|
||||||
|
self.flags.enabled = ColliderEnabled::Enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the translational part of this collider's position.
|
/// Sets the translational part of this collider's position.
|
||||||
pub fn set_translation(&mut self, translation: Vector<Real>) {
|
pub fn set_translation(&mut self, translation: Vector<Real>) {
|
||||||
self.changes.insert(ColliderChanges::POSITION);
|
self.changes.insert(ColliderChanges::POSITION);
|
||||||
@@ -402,6 +429,8 @@ pub struct ColliderBuilder {
|
|||||||
pub collision_groups: InteractionGroups,
|
pub collision_groups: InteractionGroups,
|
||||||
/// The solver groups for the collider being built.
|
/// The solver groups for the collider being built.
|
||||||
pub solver_groups: InteractionGroups,
|
pub solver_groups: InteractionGroups,
|
||||||
|
/// Will the collider being built be enabled?
|
||||||
|
pub enabled: bool,
|
||||||
/// The total force magnitude beyond which a contact force event can be emitted.
|
/// The total force magnitude beyond which a contact force event can be emitted.
|
||||||
pub contact_force_event_threshold: Real,
|
pub contact_force_event_threshold: Real,
|
||||||
}
|
}
|
||||||
@@ -424,6 +453,7 @@ impl ColliderBuilder {
|
|||||||
active_collision_types: ActiveCollisionTypes::default(),
|
active_collision_types: ActiveCollisionTypes::default(),
|
||||||
active_hooks: ActiveHooks::empty(),
|
active_hooks: ActiveHooks::empty(),
|
||||||
active_events: ActiveEvents::empty(),
|
active_events: ActiveEvents::empty(),
|
||||||
|
enabled: true,
|
||||||
contact_force_event_threshold: 0.0,
|
contact_force_event_threshold: 0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -834,6 +864,12 @@ impl ColliderBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable or disable the collider after its creation.
|
||||||
|
pub fn enabled(mut self, enabled: bool) -> Self {
|
||||||
|
self.enabled = enabled;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Builds a new collider attached to the given rigid-body.
|
/// Builds a new collider attached to the given rigid-body.
|
||||||
pub fn build(&self) -> Collider {
|
pub fn build(&self) -> Collider {
|
||||||
let shape = self.shape.clone();
|
let shape = self.shape.clone();
|
||||||
@@ -849,6 +885,11 @@ impl ColliderBuilder {
|
|||||||
active_collision_types: self.active_collision_types,
|
active_collision_types: self.active_collision_types,
|
||||||
active_hooks: self.active_hooks,
|
active_hooks: self.active_hooks,
|
||||||
active_events: self.active_events,
|
active_events: self.active_events,
|
||||||
|
enabled: if self.enabled {
|
||||||
|
ColliderEnabled::Enabled
|
||||||
|
} else {
|
||||||
|
ColliderEnabled::Disabled
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let changes = ColliderChanges::all();
|
let changes = ColliderChanges::all();
|
||||||
let pos = ColliderPosition(self.position);
|
let pos = ColliderPosition(self.position);
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ bitflags::bitflags! {
|
|||||||
/// This flags is automatically set by the `PhysicsPipeline` when the `RigidBodyChanges::DOMINANCE`
|
/// This flags is automatically set by the `PhysicsPipeline` when the `RigidBodyChanges::DOMINANCE`
|
||||||
/// or `RigidBodyChanges::TYPE` of the parent rigid-body of this collider is detected.
|
/// or `RigidBodyChanges::TYPE` of the parent rigid-body of this collider is detected.
|
||||||
const PARENT_EFFECTIVE_DOMINANCE = 1 << 7; // NF update.
|
const PARENT_EFFECTIVE_DOMINANCE = 1 << 7; // NF update.
|
||||||
|
/// Flag indicating that whether or not the collider is enabled was changed.
|
||||||
|
const ENABLED_OR_DISABLED = 1 << 8; // BF & NF updates.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,6 +374,19 @@ impl Default for ActiveCollisionTypes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||||
|
/// Enum indicating whether or not a collider is enabled.
|
||||||
|
pub enum ColliderEnabled {
|
||||||
|
/// The collider is enabled.
|
||||||
|
Enabled,
|
||||||
|
/// The collider wasn’t disabled by the user explicitly but it is attached to
|
||||||
|
/// a disabled rigid-body.
|
||||||
|
DisabledByParent,
|
||||||
|
/// The collider is disabled by the user explicitly.
|
||||||
|
Disabled,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||||
/// A set of flags for controlling collision/intersection filtering, modification, and events.
|
/// A set of flags for controlling collision/intersection filtering, modification, and events.
|
||||||
@@ -389,6 +404,8 @@ pub struct ColliderFlags {
|
|||||||
pub active_hooks: ActiveHooks,
|
pub active_hooks: ActiveHooks,
|
||||||
/// The events enabled for this collider.
|
/// The events enabled for this collider.
|
||||||
pub active_events: ActiveEvents,
|
pub active_events: ActiveEvents,
|
||||||
|
/// Whether or not the collider is enabled.
|
||||||
|
pub enabled: ColliderEnabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ColliderFlags {
|
impl Default for ColliderFlags {
|
||||||
@@ -399,6 +416,7 @@ impl Default for ColliderFlags {
|
|||||||
solver_groups: InteractionGroups::all(),
|
solver_groups: InteractionGroups::all(),
|
||||||
active_hooks: ActiveHooks::empty(),
|
active_hooks: ActiveHooks::empty(),
|
||||||
active_events: ActiveEvents::empty(),
|
active_events: ActiveEvents::empty(),
|
||||||
|
enabled: ColliderEnabled::Enabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,14 @@ impl ColliderSet {
|
|||||||
self.colliders.iter().map(|(h, c)| (ColliderHandle(h), c))
|
self.colliders.iter().map(|(h, c)| (ColliderHandle(h), c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterate through all the enabled colliders on this set.
|
||||||
|
pub fn iter_enabled(&self) -> impl Iterator<Item = (ColliderHandle, &Collider)> {
|
||||||
|
self.colliders
|
||||||
|
.iter()
|
||||||
|
.map(|(h, c)| (ColliderHandle(h), c))
|
||||||
|
.filter(|(_, c)| c.is_enabled())
|
||||||
|
}
|
||||||
|
|
||||||
/// Iterates mutably through all the colliders on this set.
|
/// Iterates mutably through all the colliders on this set.
|
||||||
#[cfg(not(feature = "dev-remove-slow-accessors"))]
|
#[cfg(not(feature = "dev-remove-slow-accessors"))]
|
||||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = (ColliderHandle, &mut Collider)> {
|
pub fn iter_mut(&mut self) -> impl Iterator<Item = (ColliderHandle, &mut Collider)> {
|
||||||
@@ -52,6 +60,12 @@ impl ColliderSet {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterates mutably through all the enabled colliders on this set.
|
||||||
|
#[cfg(not(feature = "dev-remove-slow-accessors"))]
|
||||||
|
pub fn iter_enabled_mut(&mut self) -> impl Iterator<Item = (ColliderHandle, &mut Collider)> {
|
||||||
|
self.iter_mut().filter(|(_, c)| c.is_enabled())
|
||||||
|
}
|
||||||
|
|
||||||
/// The number of colliders on this set.
|
/// The number of colliders on this set.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.colliders.len()
|
self.colliders.len()
|
||||||
@@ -268,6 +282,17 @@ impl ColliderSet {
|
|||||||
pub(crate) fn get_mut_internal(&mut self, handle: ColliderHandle) -> Option<&mut Collider> {
|
pub(crate) fn get_mut_internal(&mut self, handle: ColliderHandle) -> Option<&mut Collider> {
|
||||||
self.colliders.get_mut(handle.0)
|
self.colliders.get_mut(handle.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Just a very long name instead of `.get_mut` to make sure
|
||||||
|
// this is really the method we wanted to use instead of `get_mut_internal`.
|
||||||
|
pub(crate) fn get_mut_internal_with_modification_tracking(
|
||||||
|
&mut self,
|
||||||
|
handle: ColliderHandle,
|
||||||
|
) -> Option<&mut Collider> {
|
||||||
|
let result = self.colliders.get_mut(handle.0)?;
|
||||||
|
Self::mark_as_modified(handle, result, &mut self.modified_colliders);
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<crate::data::Index> for ColliderSet {
|
impl Index<crate::data::Index> for ColliderSet {
|
||||||
|
|||||||
@@ -127,9 +127,20 @@ impl CollisionPipeline {
|
|||||||
None,
|
None,
|
||||||
bodies,
|
bodies,
|
||||||
colliders,
|
colliders,
|
||||||
|
&mut ImpulseJointSet::new(),
|
||||||
|
&mut MultibodyJointSet::new(),
|
||||||
&modified_bodies,
|
&modified_bodies,
|
||||||
&mut modified_colliders,
|
&mut modified_colliders,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Disabled colliders are treated as if they were removed.
|
||||||
|
removed_colliders.extend(
|
||||||
|
modified_colliders
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.filter(|h| colliders.get(*h).map(|c| !c.is_enabled()).unwrap_or(false)),
|
||||||
|
);
|
||||||
|
|
||||||
self.detect_collisions(
|
self.detect_collisions(
|
||||||
prediction_distance,
|
prediction_distance,
|
||||||
broad_phase,
|
broad_phase,
|
||||||
|
|||||||
@@ -422,6 +422,7 @@ impl PhysicsPipeline {
|
|||||||
// Apply modifications.
|
// Apply modifications.
|
||||||
let mut modified_colliders = colliders.take_modified();
|
let mut modified_colliders = colliders.take_modified();
|
||||||
let mut removed_colliders = colliders.take_removed();
|
let mut removed_colliders = colliders.take_removed();
|
||||||
|
|
||||||
super::user_changes::handle_user_changes_to_colliders(
|
super::user_changes::handle_user_changes_to_colliders(
|
||||||
bodies,
|
bodies,
|
||||||
colliders,
|
colliders,
|
||||||
@@ -433,10 +434,22 @@ impl PhysicsPipeline {
|
|||||||
Some(islands),
|
Some(islands),
|
||||||
bodies,
|
bodies,
|
||||||
colliders,
|
colliders,
|
||||||
|
impulse_joints,
|
||||||
|
multibody_joints,
|
||||||
&modified_bodies,
|
&modified_bodies,
|
||||||
&mut modified_colliders,
|
&mut modified_colliders,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Disabled colliders are treated as if they were removed.
|
||||||
|
// NOTE: this must be called here, after handle_user_changes_to_rigid_bodies to take into
|
||||||
|
// account colliders disabled because of their parent rigid-body.
|
||||||
|
removed_colliders.extend(
|
||||||
|
modified_colliders
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.filter(|h| colliders.get(*h).map(|c| !c.is_enabled()).unwrap_or(false)),
|
||||||
|
);
|
||||||
|
|
||||||
// TODO: do this only on user-change.
|
// TODO: do this only on user-change.
|
||||||
// TODO: do we want some kind of automatic inverse kinematics?
|
// TODO: do we want some kind of automatic inverse kinematics?
|
||||||
for multibody in &mut multibody_joints.multibodies {
|
for multibody in &mut multibody_joints.multibodies {
|
||||||
|
|||||||
@@ -358,12 +358,12 @@ impl QueryPipeline {
|
|||||||
fn for_each(&mut self, mut f: impl FnMut(ColliderHandle, Aabb)) {
|
fn for_each(&mut self, mut f: impl FnMut(ColliderHandle, Aabb)) {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
QueryPipelineMode::CurrentPosition => {
|
QueryPipelineMode::CurrentPosition => {
|
||||||
for (h, co) in self.colliders.iter() {
|
for (h, co) in self.colliders.iter_enabled() {
|
||||||
f(h, co.shape.compute_aabb(&co.pos))
|
f(h, co.shape.compute_aabb(&co.pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueryPipelineMode::SweepTestWithNextPosition => {
|
QueryPipelineMode::SweepTestWithNextPosition => {
|
||||||
for (h, co) in self.colliders.iter() {
|
for (h, co) in self.colliders.iter_enabled() {
|
||||||
if let Some(co_parent) = co.parent {
|
if let Some(co_parent) = co.parent {
|
||||||
let rb_next_pos = &self.bodies[co_parent.handle].pos.next_position;
|
let rb_next_pos = &self.bodies[co_parent.handle].pos.next_position;
|
||||||
let next_position = rb_next_pos * co_parent.pos_wrt_parent;
|
let next_position = rb_next_pos * co_parent.pos_wrt_parent;
|
||||||
@@ -374,7 +374,7 @@ impl QueryPipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueryPipelineMode::SweepTestWithPredictedPosition { dt } => {
|
QueryPipelineMode::SweepTestWithPredictedPosition { dt } => {
|
||||||
for (h, co) in self.colliders.iter() {
|
for (h, co) in self.colliders.iter_enabled() {
|
||||||
if let Some(co_parent) = co.parent {
|
if let Some(co_parent) = co.parent {
|
||||||
let rb = &self.bodies[co_parent.handle];
|
let rb = &self.bodies[co_parent.handle];
|
||||||
let predicted_pos = rb.pos.integrate_forces_and_velocities(
|
let predicted_pos = rb.pos.integrate_forces_and_velocities(
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
use crate::dynamics::{
|
use crate::dynamics::{
|
||||||
IslandManager, RigidBodyChanges, RigidBodyHandle, RigidBodySet, RigidBodyType,
|
ImpulseJointSet, IslandManager, JointEnabled, MultibodyJointSet, RigidBodyChanges,
|
||||||
|
RigidBodyHandle, RigidBodySet, RigidBodyType,
|
||||||
|
};
|
||||||
|
use crate::geometry::{
|
||||||
|
ColliderChanges, ColliderEnabled, ColliderHandle, ColliderPosition, ColliderSet,
|
||||||
};
|
};
|
||||||
use crate::geometry::{ColliderChanges, ColliderHandle, ColliderPosition, ColliderSet};
|
|
||||||
|
|
||||||
pub(crate) fn handle_user_changes_to_colliders(
|
pub(crate) fn handle_user_changes_to_colliders(
|
||||||
bodies: &mut RigidBodySet,
|
bodies: &mut RigidBodySet,
|
||||||
@@ -21,10 +24,12 @@ pub(crate) fn handle_user_changes_to_colliders(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if co
|
if co.changes.intersects(
|
||||||
.changes
|
ColliderChanges::SHAPE
|
||||||
.intersects(ColliderChanges::SHAPE | ColliderChanges::LOCAL_MASS_PROPERTIES)
|
| ColliderChanges::LOCAL_MASS_PROPERTIES
|
||||||
{
|
| ColliderChanges::ENABLED_OR_DISABLED
|
||||||
|
| ColliderChanges::PARENT,
|
||||||
|
) {
|
||||||
if let Some(rb) = co
|
if let Some(rb) = co
|
||||||
.parent
|
.parent
|
||||||
.and_then(|p| bodies.get_mut_internal_with_modification_tracking(p.handle))
|
.and_then(|p| bodies.get_mut_internal_with_modification_tracking(p.handle))
|
||||||
@@ -40,12 +45,15 @@ pub(crate) fn handle_user_changes_to_rigid_bodies(
|
|||||||
mut islands: Option<&mut IslandManager>,
|
mut islands: Option<&mut IslandManager>,
|
||||||
bodies: &mut RigidBodySet,
|
bodies: &mut RigidBodySet,
|
||||||
colliders: &mut ColliderSet,
|
colliders: &mut ColliderSet,
|
||||||
|
impulse_joints: &mut ImpulseJointSet,
|
||||||
|
multibody_joints: &mut MultibodyJointSet,
|
||||||
modified_bodies: &[RigidBodyHandle],
|
modified_bodies: &[RigidBodyHandle],
|
||||||
modified_colliders: &mut Vec<ColliderHandle>,
|
modified_colliders: &mut Vec<ColliderHandle>,
|
||||||
) {
|
) {
|
||||||
enum FinalAction {
|
enum FinalAction {
|
||||||
UpdateActiveKinematicSetId,
|
UpdateActiveKinematicSetId(usize),
|
||||||
UpdateActiveDynamicSetId,
|
UpdateActiveDynamicSetId(usize),
|
||||||
|
RemoveFromIsland,
|
||||||
}
|
}
|
||||||
|
|
||||||
for handle in modified_bodies {
|
for handle in modified_bodies {
|
||||||
@@ -62,89 +70,95 @@ pub(crate) fn handle_user_changes_to_rigid_bodies(
|
|||||||
let mut activation = rb.activation;
|
let mut activation = rb.activation;
|
||||||
|
|
||||||
{
|
{
|
||||||
// The body's status changed. We need to make sure
|
if rb.is_enabled() {
|
||||||
// it is on the correct active set.
|
// The body's status changed. We need to make sure
|
||||||
if let Some(islands) = islands.as_deref_mut() {
|
// it is on the correct active set.
|
||||||
if changes.contains(RigidBodyChanges::TYPE) {
|
if let Some(islands) = islands.as_deref_mut() {
|
||||||
match rb.body_type {
|
if changes.contains(RigidBodyChanges::TYPE) {
|
||||||
RigidBodyType::Dynamic => {
|
match rb.body_type {
|
||||||
// Remove from the active kinematic set if it was there.
|
RigidBodyType::Dynamic => {
|
||||||
if islands.active_kinematic_set.get(ids.active_set_id) == Some(handle) {
|
// Remove from the active kinematic set if it was there.
|
||||||
islands.active_kinematic_set.swap_remove(ids.active_set_id);
|
if islands.active_kinematic_set.get(ids.active_set_id)
|
||||||
final_action = Some((
|
== Some(handle)
|
||||||
FinalAction::UpdateActiveKinematicSetId,
|
{
|
||||||
ids.active_set_id,
|
islands.active_kinematic_set.swap_remove(ids.active_set_id);
|
||||||
));
|
final_action = Some(FinalAction::UpdateActiveKinematicSetId(
|
||||||
}
|
ids.active_set_id,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// Add to the active dynamic set.
|
// Add to the active dynamic set.
|
||||||
activation.wake_up(true);
|
activation.wake_up(true);
|
||||||
// Make sure the sleep change flag is set (even if for some
|
// Make sure the sleep change flag is set (even if for some
|
||||||
// reasons the rigid-body was already awake) to make
|
// reasons the rigid-body was already awake) to make
|
||||||
// sure the code handling sleeping change adds the body to
|
// sure the code handling sleeping change adds the body to
|
||||||
// the active_dynamic_set.
|
// the active_dynamic_set.
|
||||||
changes.set(RigidBodyChanges::SLEEP, true);
|
changes.set(RigidBodyChanges::SLEEP, true);
|
||||||
}
|
|
||||||
RigidBodyType::KinematicVelocityBased
|
|
||||||
| RigidBodyType::KinematicPositionBased => {
|
|
||||||
// Remove from the active dynamic set if it was there.
|
|
||||||
if islands.active_dynamic_set.get(ids.active_set_id) == Some(handle) {
|
|
||||||
islands.active_dynamic_set.swap_remove(ids.active_set_id);
|
|
||||||
final_action = Some((
|
|
||||||
FinalAction::UpdateActiveDynamicSetId,
|
|
||||||
ids.active_set_id,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
RigidBodyType::KinematicVelocityBased
|
||||||
|
| RigidBodyType::KinematicPositionBased => {
|
||||||
|
// Remove from the active dynamic set if it was there.
|
||||||
|
if islands.active_dynamic_set.get(ids.active_set_id) == Some(handle)
|
||||||
|
{
|
||||||
|
islands.active_dynamic_set.swap_remove(ids.active_set_id);
|
||||||
|
final_action = Some(FinalAction::UpdateActiveDynamicSetId(
|
||||||
|
ids.active_set_id,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// Add to the active kinematic set.
|
// Add to the active kinematic set.
|
||||||
if islands.active_kinematic_set.get(ids.active_set_id) != Some(handle) {
|
if islands.active_kinematic_set.get(ids.active_set_id)
|
||||||
ids.active_set_id = islands.active_kinematic_set.len();
|
!= Some(handle)
|
||||||
islands.active_kinematic_set.push(*handle);
|
{
|
||||||
|
ids.active_set_id = islands.active_kinematic_set.len();
|
||||||
|
islands.active_kinematic_set.push(*handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
RigidBodyType::Fixed => {}
|
||||||
}
|
}
|
||||||
RigidBodyType::Fixed => {}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Update the positions of the colliders.
|
// Update the active kinematic set.
|
||||||
if changes.contains(RigidBodyChanges::POSITION)
|
if changes.contains(RigidBodyChanges::POSITION)
|
||||||
|| changes.contains(RigidBodyChanges::COLLIDERS)
|
|| changes.contains(RigidBodyChanges::COLLIDERS)
|
||||||
{
|
|
||||||
rb.colliders
|
|
||||||
.update_positions(colliders, modified_colliders, &rb.pos.position);
|
|
||||||
|
|
||||||
if rb.is_kinematic()
|
|
||||||
&& islands.active_kinematic_set.get(ids.active_set_id) != Some(handle)
|
|
||||||
{
|
{
|
||||||
ids.active_set_id = islands.active_kinematic_set.len();
|
if rb.is_kinematic()
|
||||||
islands.active_kinematic_set.push(*handle);
|
&& islands.active_kinematic_set.get(ids.active_set_id) != Some(handle)
|
||||||
|
{
|
||||||
|
ids.active_set_id = islands.active_kinematic_set.len();
|
||||||
|
islands.active_kinematic_set.push(*handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push the body to the active set if it is not
|
||||||
|
// sleeping and if it is not already inside of the active set.
|
||||||
|
if changes.contains(RigidBodyChanges::SLEEP)
|
||||||
|
&& rb.is_enabled()
|
||||||
|
&& !activation.sleeping // May happen if the body was put to sleep manually.
|
||||||
|
&& rb.is_dynamic() // Only dynamic bodies are in the active dynamic set.
|
||||||
|
&& islands.active_dynamic_set.get(ids.active_set_id) != Some(handle)
|
||||||
|
{
|
||||||
|
ids.active_set_id = islands.active_dynamic_set.len(); // This will handle the case where the activation_channel contains duplicates.
|
||||||
|
islands.active_dynamic_set.push(*handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Push the body to the active set if it is not
|
// Update the colliders' positions.
|
||||||
// sleeping and if it is not already inside of the active set.
|
if changes.contains(RigidBodyChanges::POSITION)
|
||||||
if changes.contains(RigidBodyChanges::SLEEP)
|
|| changes.contains(RigidBodyChanges::COLLIDERS)
|
||||||
&& !activation.sleeping // May happen if the body was put to sleep manually.
|
{
|
||||||
&& rb.is_dynamic() // Only dynamic bodies are in the active dynamic set.
|
rb.colliders
|
||||||
&& islands.active_dynamic_set.get(ids.active_set_id) != Some(handle)
|
.update_positions(colliders, modified_colliders, &rb.pos.position);
|
||||||
{
|
|
||||||
ids.active_set_id = islands.active_dynamic_set.len(); // This will handle the case where the activation_channel contains duplicates.
|
|
||||||
islands.active_dynamic_set.push(*handle);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We don't use islands. So just update the colliders' positions.
|
|
||||||
if changes.contains(RigidBodyChanges::POSITION)
|
|
||||||
|| changes.contains(RigidBodyChanges::COLLIDERS)
|
|
||||||
{
|
|
||||||
rb.colliders
|
|
||||||
.update_positions(colliders, modified_colliders, &rb.pos.position);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if changes.contains(RigidBodyChanges::DOMINANCE)
|
if changes.contains(RigidBodyChanges::DOMINANCE)
|
||||||
|| changes.contains(RigidBodyChanges::TYPE)
|
|| changes.contains(RigidBodyChanges::TYPE)
|
||||||
{
|
{
|
||||||
for handle in rb.colliders.0.iter() {
|
for handle in rb.colliders.0.iter() {
|
||||||
|
// NOTE: we can’t just use `colliders.get_mut_internal_with_modification_tracking`
|
||||||
|
// here because that would modify the `modified_colliders` inside of the `ColliderSet`
|
||||||
|
// instead of the one passed to this method.
|
||||||
let co = colliders.index_mut_internal(*handle);
|
let co = colliders.index_mut_internal(*handle);
|
||||||
if !co.changes.contains(ColliderChanges::MODIFIED) {
|
if !co.changes.contains(ColliderChanges::MODIFIED) {
|
||||||
modified_colliders.push(*handle);
|
modified_colliders.push(*handle);
|
||||||
@@ -165,6 +179,43 @@ pub(crate) fn handle_user_changes_to_rigid_bodies(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if changes.contains(RigidBodyChanges::ENABLED_OR_DISABLED) {
|
||||||
|
// Propagate the rigid-body’s enabled/disable status to its colliders.
|
||||||
|
for handle in rb.colliders.0.iter() {
|
||||||
|
// NOTE: we can’t just use `colliders.get_mut_internal_with_modification_tracking`
|
||||||
|
// here because that would modify the `modified_colliders` inside of the `ColliderSet`
|
||||||
|
// instead of the one passed to this method.
|
||||||
|
let co = colliders.index_mut_internal(*handle);
|
||||||
|
if !co.changes.contains(ColliderChanges::MODIFIED) {
|
||||||
|
modified_colliders.push(*handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if rb.enabled && co.flags.enabled == ColliderEnabled::DisabledByParent {
|
||||||
|
co.flags.enabled = ColliderEnabled::Enabled;
|
||||||
|
} else if !rb.enabled && co.flags.enabled == ColliderEnabled::Enabled {
|
||||||
|
co.flags.enabled = ColliderEnabled::DisabledByParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
co.changes |= ColliderChanges::MODIFIED | ColliderChanges::ENABLED_OR_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Propagate the rigid-body’s enabled/disable status to its attached impulse joints.
|
||||||
|
impulse_joints.map_attached_joints_mut(*handle, |_, _, _, joint| {
|
||||||
|
if rb.enabled && joint.data.enabled == JointEnabled::DisabledByAttachedBody {
|
||||||
|
joint.data.enabled = JointEnabled::Enabled;
|
||||||
|
} else if !rb.enabled && joint.data.enabled == JointEnabled::Enabled {
|
||||||
|
joint.data.enabled = JointEnabled::DisabledByAttachedBody;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME: Propagate the rigid-body’s enabled/disable status to its attached multibody joints.
|
||||||
|
|
||||||
|
// Remove the rigid-body from the island manager.
|
||||||
|
if !rb.enabled {
|
||||||
|
final_action = Some(FinalAction::RemoveFromIsland);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rb.changes = RigidBodyChanges::empty();
|
rb.changes = RigidBodyChanges::empty();
|
||||||
rb.ids = ids;
|
rb.ids = ids;
|
||||||
rb.activation = activation;
|
rb.activation = activation;
|
||||||
@@ -172,15 +223,25 @@ pub(crate) fn handle_user_changes_to_rigid_bodies(
|
|||||||
|
|
||||||
// Adjust some ids, if needed.
|
// Adjust some ids, if needed.
|
||||||
if let Some(islands) = islands.as_deref_mut() {
|
if let Some(islands) = islands.as_deref_mut() {
|
||||||
if let Some((action, id)) = final_action {
|
if let Some(action) = final_action {
|
||||||
let active_set = match action {
|
match action {
|
||||||
FinalAction::UpdateActiveKinematicSetId => &mut islands.active_kinematic_set,
|
FinalAction::RemoveFromIsland => {
|
||||||
FinalAction::UpdateActiveDynamicSetId => &mut islands.active_dynamic_set,
|
let ids = rb.ids;
|
||||||
|
islands.rigid_body_removed(*handle, &ids, bodies);
|
||||||
|
}
|
||||||
|
FinalAction::UpdateActiveKinematicSetId(id) => {
|
||||||
|
let active_set = &mut islands.active_kinematic_set;
|
||||||
|
if id < active_set.len() {
|
||||||
|
bodies.index_mut_internal(active_set[id]).ids.active_set_id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FinalAction::UpdateActiveDynamicSetId(id) => {
|
||||||
|
let active_set = &mut islands.active_dynamic_set;
|
||||||
|
if id < active_set.len() {
|
||||||
|
bodies.index_mut_internal(active_set[id]).ids.active_set_id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if id < active_set.len() {
|
|
||||||
bodies.index_mut_internal(active_set[id]).ids.active_set_id = id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user