Fix user changes handling (#803)
* add failing test from @Johannes0021 * apply fix on update_positions * apply fix on ColliderSet::iter_mut * fix clippy.. * more complete test * feat: refactor modified sets into a wrapper to avoid future mistakes * chore: fix typos --------- Co-authored-by: Sébastien Crozet <sebcrozet@dimforge.com>
This commit is contained in:
@@ -2,8 +2,10 @@
|
||||
|
||||
pub use self::arena::{Arena, Index};
|
||||
pub use self::coarena::Coarena;
|
||||
pub(crate) use self::modified_objects::{HasModifiedFlag, ModifiedObjects};
|
||||
|
||||
pub mod arena;
|
||||
mod coarena;
|
||||
pub(crate) mod graph;
|
||||
mod modified_objects;
|
||||
pub mod pubsub;
|
||||
|
||||
65
src/data/modified_objects.rs
Normal file
65
src/data/modified_objects.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
|
||||
/// Contains handles of modified objects.
|
||||
///
|
||||
/// This is a wrapper over a `Vec` to ensure we don’t forget to set the object’s
|
||||
/// MODIFIED flag when adding it to this set.
|
||||
/// It is possible to bypass the wrapper with `.as_mut_internal`. But this should only
|
||||
/// be done for internal engine usage (like the physics pipeline).
|
||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct ModifiedObjects<Handle, Object>(Vec<Handle>, PhantomData<Object>);
|
||||
|
||||
impl<Handle, Object> Default for ModifiedObjects<Handle, Object> {
|
||||
fn default() -> Self {
|
||||
Self(Vec::new(), PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait HasModifiedFlag {
|
||||
fn has_modified_flag(&self) -> bool;
|
||||
fn set_modified_flag(&mut self);
|
||||
}
|
||||
|
||||
impl<Handle, Object> Deref for ModifiedObjects<Handle, Object> {
|
||||
type Target = Vec<Handle>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<Handle, Object: HasModifiedFlag> ModifiedObjects<Handle, Object> {
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self(Vec::with_capacity(capacity), PhantomData)
|
||||
}
|
||||
|
||||
/// Remove every handle from this set.
|
||||
///
|
||||
/// Note that the corresponding object MODIFIED flags won’t be reset automatically by this function.
|
||||
pub fn clear(&mut self) {
|
||||
self.0.clear()
|
||||
}
|
||||
|
||||
/// Pushes a object handle to this set after checking that it doesn’t have the MODIFIED
|
||||
/// flag set.
|
||||
///
|
||||
/// This will also set the object’s MODIFIED flag.
|
||||
pub fn push_once(&mut self, handle: Handle, object: &mut Object) {
|
||||
if !object.has_modified_flag() {
|
||||
self.push_unchecked(handle, object);
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes an object handle to this set without checking if the object already has the MODIFIED
|
||||
/// flags.
|
||||
///
|
||||
/// Only use in situation where you are certain (due to other contextual information) that
|
||||
/// the object isn’t already in the set.
|
||||
///
|
||||
/// This will also set the object’s MODIFIED flag.
|
||||
pub fn push_unchecked(&mut self, handle: Handle, object: &mut Object) {
|
||||
object.set_modified_flag();
|
||||
self.0.push(handle);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ pub(crate) use self::joint::JointGraphEdge;
|
||||
pub(crate) use self::joint::JointIndex;
|
||||
pub use self::joint::*;
|
||||
pub use self::rigid_body_components::*;
|
||||
pub(crate) use self::rigid_body_set::ModifiedRigidBodies;
|
||||
// #[cfg(not(feature = "parallel"))]
|
||||
pub(crate) use self::solver::IslandSolver;
|
||||
// #[cfg(feature = "parallel")]
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::control::PdErrors;
|
||||
use crate::dynamics::MassProperties;
|
||||
use crate::geometry::{
|
||||
ColliderChanges, ColliderHandle, ColliderMassProps, ColliderParent, ColliderPosition,
|
||||
ColliderSet, ColliderShape,
|
||||
ColliderSet, ColliderShape, ModifiedColliders,
|
||||
};
|
||||
use crate::math::{
|
||||
AngVector, AngularInertia, Isometry, Point, Real, Rotation, Translation, Vector,
|
||||
@@ -1020,10 +1020,10 @@ impl RigidBodyColliders {
|
||||
}
|
||||
|
||||
/// Update the positions of all the colliders attached to this rigid-body.
|
||||
pub fn update_positions(
|
||||
pub(crate) fn update_positions(
|
||||
&self,
|
||||
colliders: &mut ColliderSet,
|
||||
modified_colliders: &mut Vec<ColliderHandle>,
|
||||
modified_colliders: &mut ModifiedColliders,
|
||||
parent_pos: &Isometry<Real>,
|
||||
) {
|
||||
for handle in &self.0 {
|
||||
@@ -1031,12 +1031,10 @@ impl RigidBodyColliders {
|
||||
let co = colliders.index_mut_internal(*handle);
|
||||
let new_pos = parent_pos * co.parent.as_ref().unwrap().pos_wrt_parent;
|
||||
|
||||
if !co.changes.contains(ColliderChanges::MODIFIED) {
|
||||
modified_colliders.push(*handle);
|
||||
}
|
||||
|
||||
// Set the modification flag so we can benefit from the modification-tracking
|
||||
// when updating the narrow-phase/broad-phase afterwards.
|
||||
modified_colliders.push_once(*handle, co);
|
||||
|
||||
co.changes |= ColliderChanges::POSITION;
|
||||
co.pos = ColliderPosition(new_pos);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::data::Arena;
|
||||
use crate::data::{Arena, HasModifiedFlag, ModifiedObjects};
|
||||
use crate::dynamics::{
|
||||
ImpulseJointSet, IslandManager, MultibodyJointSet, RigidBody, RigidBodyChanges, RigidBodyHandle,
|
||||
};
|
||||
@@ -22,6 +22,20 @@ impl BodyPair {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type ModifiedRigidBodies = ModifiedObjects<RigidBodyHandle, RigidBody>;
|
||||
|
||||
impl HasModifiedFlag for RigidBody {
|
||||
#[inline]
|
||||
fn has_modified_flag(&self) -> bool {
|
||||
self.changes.contains(RigidBodyChanges::MODIFIED)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_modified_flag(&mut self) {
|
||||
self.changes |= RigidBodyChanges::MODIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||
#[derive(Clone, Default, Debug)]
|
||||
/// A set of rigid bodies that can be handled by a physics pipeline.
|
||||
@@ -31,7 +45,7 @@ pub struct RigidBodySet {
|
||||
// parallelism because the `Receiver` breaks the Sync impl.
|
||||
// Could we avoid this?
|
||||
pub(crate) bodies: Arena<RigidBody>,
|
||||
pub(crate) modified_bodies: Vec<RigidBodyHandle>,
|
||||
pub(crate) modified_bodies: ModifiedRigidBodies,
|
||||
}
|
||||
|
||||
impl RigidBodySet {
|
||||
@@ -39,7 +53,7 @@ impl RigidBodySet {
|
||||
pub fn new() -> Self {
|
||||
RigidBodySet {
|
||||
bodies: Arena::new(),
|
||||
modified_bodies: Vec::new(),
|
||||
modified_bodies: ModifiedObjects::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,11 +61,11 @@ impl RigidBodySet {
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
RigidBodySet {
|
||||
bodies: Arena::with_capacity(capacity),
|
||||
modified_bodies: Vec::with_capacity(capacity),
|
||||
modified_bodies: ModifiedRigidBodies::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn take_modified(&mut self) -> Vec<RigidBodyHandle> {
|
||||
pub(crate) fn take_modified(&mut self) -> ModifiedRigidBodies {
|
||||
std::mem::take(&mut self.modified_bodies)
|
||||
}
|
||||
|
||||
@@ -79,7 +93,10 @@ impl RigidBodySet {
|
||||
rb.changes.set(RigidBodyChanges::all(), true);
|
||||
|
||||
let handle = RigidBodyHandle(self.bodies.insert(rb));
|
||||
self.modified_bodies.push(handle);
|
||||
// Using push_unchecked because this is a brand new rigid-body with the MODIFIED
|
||||
// flags set but isn’t in the modified_bodies yet.
|
||||
self.modified_bodies
|
||||
.push_unchecked(handle, &mut self.bodies[handle.0]);
|
||||
handle
|
||||
}
|
||||
|
||||
@@ -152,7 +169,7 @@ impl RigidBodySet {
|
||||
pub fn get_unknown_gen_mut(&mut self, i: u32) -> Option<(&mut RigidBody, RigidBodyHandle)> {
|
||||
let (rb, handle) = self.bodies.get_unknown_gen_mut(i)?;
|
||||
let handle = RigidBodyHandle(handle);
|
||||
Self::mark_as_modified(handle, rb, &mut self.modified_bodies);
|
||||
self.modified_bodies.push_once(handle, rb);
|
||||
Some((rb, handle))
|
||||
}
|
||||
|
||||
@@ -161,22 +178,11 @@ impl RigidBodySet {
|
||||
self.bodies.get(handle.0)
|
||||
}
|
||||
|
||||
pub(crate) fn mark_as_modified(
|
||||
handle: RigidBodyHandle,
|
||||
rb: &mut RigidBody,
|
||||
modified_bodies: &mut Vec<RigidBodyHandle>,
|
||||
) {
|
||||
if !rb.changes.contains(RigidBodyChanges::MODIFIED) {
|
||||
rb.changes = RigidBodyChanges::MODIFIED;
|
||||
modified_bodies.push(handle);
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the rigid-body with the given handle.
|
||||
#[cfg(not(feature = "dev-remove-slow-accessors"))]
|
||||
pub fn get_mut(&mut self, handle: RigidBodyHandle) -> Option<&mut RigidBody> {
|
||||
let result = self.bodies.get_mut(handle.0)?;
|
||||
Self::mark_as_modified(handle, result, &mut self.modified_bodies);
|
||||
self.modified_bodies.push_once(handle, result);
|
||||
Some(result)
|
||||
}
|
||||
|
||||
@@ -195,7 +201,7 @@ impl RigidBodySet {
|
||||
handle: RigidBodyHandle,
|
||||
) -> Option<&mut RigidBody> {
|
||||
let result = self.bodies.get_mut(handle.0)?;
|
||||
Self::mark_as_modified(handle, result, &mut self.modified_bodies);
|
||||
self.modified_bodies.push_once(handle, result);
|
||||
Some(result)
|
||||
}
|
||||
|
||||
@@ -210,7 +216,9 @@ impl RigidBodySet {
|
||||
self.modified_bodies.clear();
|
||||
let modified_bodies = &mut self.modified_bodies;
|
||||
self.bodies.iter_mut().map(move |(h, b)| {
|
||||
modified_bodies.push(RigidBodyHandle(h));
|
||||
// NOTE: using `push_unchecked` because we just cleared `modified_bodies`
|
||||
// before iterating.
|
||||
modified_bodies.push_unchecked(RigidBodyHandle(h), b);
|
||||
(RigidBodyHandle(h), b)
|
||||
})
|
||||
}
|
||||
@@ -256,7 +264,7 @@ impl Index<crate::data::Index> for RigidBodySet {
|
||||
impl IndexMut<RigidBodyHandle> for RigidBodySet {
|
||||
fn index_mut(&mut self, handle: RigidBodyHandle) -> &mut RigidBody {
|
||||
let rb = &mut self.bodies[handle.0];
|
||||
Self::mark_as_modified(handle, rb, &mut self.modified_bodies);
|
||||
self.modified_bodies.push_once(handle, rb);
|
||||
rb
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,30 @@
|
||||
use crate::data::arena::Arena;
|
||||
use crate::data::{HasModifiedFlag, ModifiedObjects};
|
||||
use crate::dynamics::{IslandManager, RigidBodyHandle, RigidBodySet};
|
||||
use crate::geometry::{Collider, ColliderChanges, ColliderHandle, ColliderParent};
|
||||
use crate::math::Isometry;
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
pub(crate) type ModifiedColliders = ModifiedObjects<ColliderHandle, Collider>;
|
||||
|
||||
impl HasModifiedFlag for Collider {
|
||||
#[inline]
|
||||
fn has_modified_flag(&self) -> bool {
|
||||
self.changes.contains(ColliderChanges::MODIFIED)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_modified_flag(&mut self) {
|
||||
self.changes |= ColliderChanges::MODIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||
#[derive(Clone, Default, Debug)]
|
||||
/// A set of colliders that can be handled by a physics `World`.
|
||||
pub struct ColliderSet {
|
||||
pub(crate) colliders: Arena<Collider>,
|
||||
pub(crate) modified_colliders: Vec<ColliderHandle>,
|
||||
pub(crate) modified_colliders: ModifiedColliders,
|
||||
pub(crate) removed_colliders: Vec<ColliderHandle>,
|
||||
}
|
||||
|
||||
@@ -18,7 +33,7 @@ impl ColliderSet {
|
||||
pub fn new() -> Self {
|
||||
ColliderSet {
|
||||
colliders: Arena::new(),
|
||||
modified_colliders: Vec::new(),
|
||||
modified_colliders: Default::default(),
|
||||
removed_colliders: Vec::new(),
|
||||
}
|
||||
}
|
||||
@@ -29,12 +44,12 @@ impl ColliderSet {
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
ColliderSet {
|
||||
colliders: Arena::with_capacity(capacity),
|
||||
modified_colliders: Vec::with_capacity(capacity),
|
||||
modified_colliders: ModifiedColliders::with_capacity(capacity),
|
||||
removed_colliders: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn take_modified(&mut self) -> Vec<ColliderHandle> {
|
||||
pub(crate) fn take_modified(&mut self) -> ModifiedColliders {
|
||||
std::mem::take(&mut self.modified_colliders)
|
||||
}
|
||||
|
||||
@@ -65,9 +80,11 @@ impl ColliderSet {
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = (ColliderHandle, &mut Collider)> {
|
||||
self.modified_colliders.clear();
|
||||
let modified_colliders = &mut self.modified_colliders;
|
||||
self.colliders.iter_mut().map(move |(h, b)| {
|
||||
modified_colliders.push(ColliderHandle(h));
|
||||
(ColliderHandle(h), b)
|
||||
self.colliders.iter_mut().map(move |(h, co)| {
|
||||
// NOTE: we push unchecked here since we are just re-populating the
|
||||
// `modified_colliders` set that we just cleared before iteration.
|
||||
modified_colliders.push_unchecked(ColliderHandle(h), co);
|
||||
(ColliderHandle(h), co)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -100,7 +117,11 @@ impl ColliderSet {
|
||||
coll.reset_internal_references();
|
||||
coll.parent = None;
|
||||
let handle = ColliderHandle(self.colliders.insert(coll));
|
||||
self.modified_colliders.push(handle);
|
||||
// NOTE: we push unchecked because this is a brand-new collider
|
||||
// so it was initialized with the changed flag but isn’t in
|
||||
// the set yet.
|
||||
self.modified_colliders
|
||||
.push_unchecked(handle, &mut self.colliders[handle.0]);
|
||||
handle
|
||||
}
|
||||
|
||||
@@ -131,9 +152,12 @@ impl ColliderSet {
|
||||
.get_mut_internal_with_modification_tracking(parent_handle)
|
||||
.expect("Parent rigid body not found.");
|
||||
let handle = ColliderHandle(self.colliders.insert(coll));
|
||||
self.modified_colliders.push(handle);
|
||||
|
||||
let coll = self.colliders.get_mut(handle.0).unwrap();
|
||||
// NOTE: we push unchecked because this is a brand-new collider
|
||||
// so it was initialized with the changed flag but isn’t in
|
||||
// the set yet.
|
||||
self.modified_colliders.push_unchecked(handle, coll);
|
||||
|
||||
parent.add_collider_internal(
|
||||
handle,
|
||||
coll.parent.as_mut().unwrap(),
|
||||
@@ -258,7 +282,7 @@ impl ColliderSet {
|
||||
pub fn get_unknown_gen_mut(&mut self, i: u32) -> Option<(&mut Collider, ColliderHandle)> {
|
||||
let (collider, handle) = self.colliders.get_unknown_gen_mut(i)?;
|
||||
let handle = ColliderHandle(handle);
|
||||
Self::mark_as_modified(handle, collider, &mut self.modified_colliders);
|
||||
self.modified_colliders.push_once(handle, collider);
|
||||
Some((collider, handle))
|
||||
}
|
||||
|
||||
@@ -267,22 +291,11 @@ impl ColliderSet {
|
||||
self.colliders.get(handle.0)
|
||||
}
|
||||
|
||||
fn mark_as_modified(
|
||||
handle: ColliderHandle,
|
||||
collider: &mut Collider,
|
||||
modified_colliders: &mut Vec<ColliderHandle>,
|
||||
) {
|
||||
if !collider.changes.contains(ColliderChanges::MODIFIED) {
|
||||
collider.changes = ColliderChanges::MODIFIED;
|
||||
modified_colliders.push(handle);
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the collider with the given handle.
|
||||
#[cfg(not(feature = "dev-remove-slow-accessors"))]
|
||||
pub fn get_mut(&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);
|
||||
self.modified_colliders.push_once(handle, result);
|
||||
Some(result)
|
||||
}
|
||||
|
||||
@@ -302,7 +315,7 @@ impl ColliderSet {
|
||||
handle: ColliderHandle,
|
||||
) -> Option<&mut Collider> {
|
||||
let result = self.colliders.get_mut(handle.0)?;
|
||||
Self::mark_as_modified(handle, result, &mut self.modified_colliders);
|
||||
self.modified_colliders.push_once(handle, result);
|
||||
Some(result)
|
||||
}
|
||||
}
|
||||
@@ -327,7 +340,7 @@ impl Index<ColliderHandle> for ColliderSet {
|
||||
impl IndexMut<ColliderHandle> for ColliderSet {
|
||||
fn index_mut(&mut self, handle: ColliderHandle) -> &mut Collider {
|
||||
let collider = &mut self.colliders[handle.0];
|
||||
Self::mark_as_modified(handle, collider, &mut self.modified_colliders);
|
||||
self.modified_colliders.push_once(handle, collider);
|
||||
collider
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +182,7 @@ impl ContactForceEvent {
|
||||
}
|
||||
|
||||
pub(crate) use self::broad_phase::BroadPhaseProxyIndex;
|
||||
pub(crate) use self::collider_set::ModifiedColliders;
|
||||
pub(crate) use self::narrow_phase::ContactManifoldIndex;
|
||||
pub(crate) use parry::partitioning::Qbvh;
|
||||
pub use parry::shape::*;
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
use crate::dynamics::{ImpulseJointSet, MultibodyJointSet};
|
||||
use crate::geometry::{
|
||||
BroadPhase, BroadPhasePairEvent, ColliderChanges, ColliderHandle, ColliderPair, NarrowPhase,
|
||||
BroadPhase, BroadPhasePairEvent, ColliderChanges, ColliderHandle, ColliderPair,
|
||||
ModifiedColliders, NarrowPhase,
|
||||
};
|
||||
use crate::math::Real;
|
||||
use crate::pipeline::{EventHandler, PhysicsHooks, QueryPipeline};
|
||||
@@ -97,13 +98,15 @@ impl CollisionPipeline {
|
||||
fn clear_modified_colliders(
|
||||
&mut self,
|
||||
colliders: &mut ColliderSet,
|
||||
modified_colliders: &mut Vec<ColliderHandle>,
|
||||
modified_colliders: &mut ModifiedColliders,
|
||||
) {
|
||||
for handle in modified_colliders.drain(..) {
|
||||
if let Some(co) = colliders.get_mut_internal(handle) {
|
||||
for handle in modified_colliders.iter() {
|
||||
if let Some(co) = colliders.get_mut_internal(*handle) {
|
||||
co.changes = ColliderChanges::empty();
|
||||
}
|
||||
}
|
||||
|
||||
modified_colliders.clear();
|
||||
}
|
||||
|
||||
/// Executes one step of the collision detection.
|
||||
|
||||
@@ -7,14 +7,15 @@ use crate::dynamics::IslandSolver;
|
||||
use crate::dynamics::JointGraphEdge;
|
||||
use crate::dynamics::{
|
||||
CCDSolver, ImpulseJointSet, IntegrationParameters, IslandManager, MultibodyJointSet,
|
||||
RigidBodyChanges, RigidBodyHandle, RigidBodyPosition, RigidBodyType,
|
||||
RigidBodyChanges, RigidBodyPosition, RigidBodyType,
|
||||
};
|
||||
use crate::geometry::{
|
||||
BroadPhase, BroadPhasePairEvent, ColliderChanges, ColliderHandle, ColliderPair,
|
||||
ContactManifoldIndex, NarrowPhase, TemporaryInteractionIndex,
|
||||
ContactManifoldIndex, ModifiedColliders, NarrowPhase, TemporaryInteractionIndex,
|
||||
};
|
||||
use crate::math::{Real, Vector};
|
||||
use crate::pipeline::{EventHandler, PhysicsHooks, QueryPipeline};
|
||||
use crate::prelude::ModifiedRigidBodies;
|
||||
use {crate::dynamics::RigidBodySet, crate::geometry::ColliderSet};
|
||||
|
||||
/// The physics pipeline, responsible for stepping the whole physics simulation.
|
||||
@@ -68,25 +69,29 @@ impl PhysicsPipeline {
|
||||
fn clear_modified_colliders(
|
||||
&mut self,
|
||||
colliders: &mut ColliderSet,
|
||||
modified_colliders: &mut Vec<ColliderHandle>,
|
||||
modified_colliders: &mut ModifiedColliders,
|
||||
) {
|
||||
for handle in modified_colliders.drain(..) {
|
||||
if let Some(co) = colliders.get_mut_internal(handle) {
|
||||
for handle in modified_colliders.iter() {
|
||||
if let Some(co) = colliders.get_mut_internal(*handle) {
|
||||
co.changes = ColliderChanges::empty();
|
||||
}
|
||||
}
|
||||
|
||||
modified_colliders.clear();
|
||||
}
|
||||
|
||||
fn clear_modified_bodies(
|
||||
&mut self,
|
||||
bodies: &mut RigidBodySet,
|
||||
modified_bodies: &mut Vec<RigidBodyHandle>,
|
||||
modified_bodies: &mut ModifiedRigidBodies,
|
||||
) {
|
||||
for handle in modified_bodies.drain(..) {
|
||||
if let Some(rb) = bodies.get_mut_internal(handle) {
|
||||
for handle in modified_bodies.iter() {
|
||||
if let Some(rb) = bodies.get_mut_internal(*handle) {
|
||||
rb.changes = RigidBodyChanges::empty();
|
||||
}
|
||||
}
|
||||
|
||||
modified_bodies.clear();
|
||||
}
|
||||
|
||||
fn detect_collisions(
|
||||
@@ -359,7 +364,7 @@ impl PhysicsPipeline {
|
||||
islands: &IslandManager,
|
||||
bodies: &mut RigidBodySet,
|
||||
colliders: &mut ColliderSet,
|
||||
modified_colliders: &mut Vec<ColliderHandle>,
|
||||
modified_colliders: &mut ModifiedColliders,
|
||||
) {
|
||||
// Set the rigid-bodies and kinematic bodies to their final position.
|
||||
for handle in islands.iter_active_bodies() {
|
||||
@@ -1011,4 +1016,107 @@ mod test {
|
||||
assert!(rotation.w.is_finite());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "dim2")]
|
||||
fn test_multi_sap_disable_body() {
|
||||
use na::vector;
|
||||
let mut rigid_body_set = RigidBodySet::new();
|
||||
let mut collider_set = ColliderSet::new();
|
||||
|
||||
/* Create the ground. */
|
||||
let collider = ColliderBuilder::cuboid(100.0, 0.1).build();
|
||||
collider_set.insert(collider);
|
||||
|
||||
/* Create the bouncing ball. */
|
||||
let rigid_body = RigidBodyBuilder::dynamic()
|
||||
.translation(vector![0.0, 10.0])
|
||||
.build();
|
||||
let collider = ColliderBuilder::ball(0.5).restitution(0.7).build();
|
||||
let ball_body_handle = rigid_body_set.insert(rigid_body);
|
||||
collider_set.insert_with_parent(collider, ball_body_handle, &mut rigid_body_set);
|
||||
|
||||
/* Create other structures necessary for the simulation. */
|
||||
let gravity = vector![0.0, -9.81];
|
||||
let integration_parameters = IntegrationParameters::default();
|
||||
let mut physics_pipeline = PhysicsPipeline::new();
|
||||
let mut island_manager = IslandManager::new();
|
||||
let mut broad_phase = BroadPhaseMultiSap::new();
|
||||
let mut narrow_phase = NarrowPhase::new();
|
||||
let mut impulse_joint_set = ImpulseJointSet::new();
|
||||
let mut multibody_joint_set = MultibodyJointSet::new();
|
||||
let mut ccd_solver = CCDSolver::new();
|
||||
let physics_hooks = ();
|
||||
let event_handler = ();
|
||||
|
||||
physics_pipeline.step(
|
||||
&gravity,
|
||||
&integration_parameters,
|
||||
&mut island_manager,
|
||||
&mut broad_phase,
|
||||
&mut narrow_phase,
|
||||
&mut rigid_body_set,
|
||||
&mut collider_set,
|
||||
&mut impulse_joint_set,
|
||||
&mut multibody_joint_set,
|
||||
&mut ccd_solver,
|
||||
None,
|
||||
&physics_hooks,
|
||||
&event_handler,
|
||||
);
|
||||
|
||||
// Test RigidBodyChanges::POSITION and disable
|
||||
{
|
||||
let ball_body = &mut rigid_body_set[ball_body_handle];
|
||||
|
||||
// Also, change the translation and rotation to different values
|
||||
ball_body.set_translation(vector![1.0, 1.0], true);
|
||||
ball_body.set_rotation(nalgebra::UnitComplex::new(1.0), true);
|
||||
|
||||
ball_body.set_enabled(false);
|
||||
}
|
||||
|
||||
physics_pipeline.step(
|
||||
&gravity,
|
||||
&integration_parameters,
|
||||
&mut island_manager,
|
||||
&mut broad_phase,
|
||||
&mut narrow_phase,
|
||||
&mut rigid_body_set,
|
||||
&mut collider_set,
|
||||
&mut impulse_joint_set,
|
||||
&mut multibody_joint_set,
|
||||
&mut ccd_solver,
|
||||
None,
|
||||
&physics_hooks,
|
||||
&event_handler,
|
||||
);
|
||||
|
||||
// Test RigidBodyChanges::POSITION and enable
|
||||
{
|
||||
let ball_body = &mut rigid_body_set[ball_body_handle];
|
||||
|
||||
// Also, change the translation and rotation to different values
|
||||
ball_body.set_translation(vector![0.0, 0.0], true);
|
||||
ball_body.set_rotation(nalgebra::UnitComplex::new(0.0), true);
|
||||
|
||||
ball_body.set_enabled(true);
|
||||
}
|
||||
|
||||
physics_pipeline.step(
|
||||
&gravity,
|
||||
&integration_parameters,
|
||||
&mut island_manager,
|
||||
&mut broad_phase,
|
||||
&mut narrow_phase,
|
||||
&mut rigid_body_set,
|
||||
&mut collider_set,
|
||||
&mut impulse_joint_set,
|
||||
&mut multibody_joint_set,
|
||||
&mut ccd_solver,
|
||||
None,
|
||||
&physics_hooks,
|
||||
&event_handler,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::dynamics::{
|
||||
};
|
||||
use crate::geometry::{
|
||||
ColliderChanges, ColliderEnabled, ColliderHandle, ColliderPosition, ColliderSet,
|
||||
ModifiedColliders,
|
||||
};
|
||||
|
||||
pub(crate) fn handle_user_changes_to_colliders(
|
||||
@@ -48,7 +49,7 @@ pub(crate) fn handle_user_changes_to_rigid_bodies(
|
||||
impulse_joints: &mut ImpulseJointSet,
|
||||
_multibody_joints: &mut MultibodyJointSet, // FIXME: propagate disabled state to multibodies
|
||||
modified_bodies: &[RigidBodyHandle],
|
||||
modified_colliders: &mut Vec<ColliderHandle>,
|
||||
modified_colliders: &mut ModifiedColliders,
|
||||
) {
|
||||
enum FinalAction {
|
||||
UpdateActiveKinematicSetId(usize),
|
||||
@@ -150,12 +151,8 @@ pub(crate) fn handle_user_changes_to_rigid_bodies(
|
||||
// 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);
|
||||
}
|
||||
|
||||
co.changes |=
|
||||
ColliderChanges::MODIFIED | ColliderChanges::PARENT_EFFECTIVE_DOMINANCE;
|
||||
modified_colliders.push_once(*handle, co);
|
||||
co.changes |= ColliderChanges::PARENT_EFFECTIVE_DOMINANCE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,9 +163,7 @@ pub(crate) fn handle_user_changes_to_rigid_bodies(
|
||||
// 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);
|
||||
}
|
||||
modified_colliders.push_once(*handle, co);
|
||||
|
||||
if rb.enabled && co.flags.enabled == ColliderEnabled::DisabledByParent {
|
||||
co.flags.enabled = ColliderEnabled::Enabled;
|
||||
@@ -176,7 +171,7 @@ pub(crate) fn handle_user_changes_to_rigid_bodies(
|
||||
co.flags.enabled = ColliderEnabled::DisabledByParent;
|
||||
}
|
||||
|
||||
co.changes |= ColliderChanges::MODIFIED | ColliderChanges::ENABLED_OR_DISABLED;
|
||||
co.changes |= ColliderChanges::ENABLED_OR_DISABLED;
|
||||
}
|
||||
|
||||
// Propagate the rigid-body’s enabled/disable status to its attached impulse joints.
|
||||
|
||||
Reference in New Issue
Block a user