From 12c10703312820e6f8a8589b3fc57e181845e4ec Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Thu, 26 Sep 2024 18:09:33 +0200 Subject: [PATCH 1/7] reproduction for case 1 (no collision) --- src/geometry/narrow_phase.rs | 119 +++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index 908f83ea..4d2f944a 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -1168,3 +1168,122 @@ impl NarrowPhase { } } } + +#[cfg(test)] +#[cfg(feature = "f32")] +//#[cfg(feature = "dim3")] +mod test { + use na::vector; + + use crate::prelude::{ + CCDSolver, ColliderBuilder, DefaultBroadPhase, IntegrationParameters, PhysicsPipeline, + QueryPipeline, RigidBodyBuilder, + }; + + use super::*; + + /// Test for https://github.com/dimforge/rapier/issues/734. + #[test] + pub fn reparent() { + let mut rigid_body_set = RigidBodySet::new(); + let mut collider_set = ColliderSet::new(); + + /* Create the ground. */ + let collider = ColliderBuilder::ball(0.5); + + /* Create body 1, which will contain both colliders at first. */ + let rigid_body_1 = RigidBodyBuilder::dynamic() + .translation(vector![0.0, 10.0, 0.0]) + .build(); + let body_1_handle = rigid_body_set.insert(rigid_body_1); + + /* Create collider 1. Parent it to rigid body 1. */ + let collider_1_handle = + collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set); + + /* Create collider 2. Parent it to rigid body 1. */ + //let collider_2_handle = + // collider_set.insert_with_parent(collider.build(), body_2_handle, &mut rigid_body_set); + + /* Create collider 2. Parent it to rigid body 1. */ + let collider_2_handle = + collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set); + + /* Create body 2. No attached colliders yet. */ + let rigid_body_2 = RigidBodyBuilder::dynamic() + .translation(vector![0.0, 10.0, 0.0]) + .build(); + let body_2_handle = rigid_body_set.insert(rigid_body_2); + + /* Create other structures necessary for the simulation. */ + let gravity = vector![0.0, 0.0, 0.0]; + let integration_parameters = IntegrationParameters::default(); + let mut physics_pipeline = PhysicsPipeline::new(); + let mut island_manager = IslandManager::new(); + let mut broad_phase = DefaultBroadPhase::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 mut query_pipeline = QueryPipeline::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, + Some(&mut query_pipeline), + &physics_hooks, + &event_handler, + ); + let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos; + let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos; + assert!( + (collider_1_position.translation.vector - collider_2_position.translation.vector) + .magnitude() + < 0.5f32 + ); + + collider_set.set_parent(collider_2_handle, Some(body_2_handle), &mut rigid_body_set); + + /* Run the game loop, stepping the simulation once per frame. */ + for _ in 0..200 { + 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, + Some(&mut query_pipeline), + &physics_hooks, + &event_handler, + ); + + let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos; + let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos; + println!("collider 1 position: {}", collider_1_position.translation); + println!("collider 2 position: {}", collider_2_position.translation); + } + + let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos; + let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos; + assert!( + (collider_1_position.translation.vector - collider_2_position.translation.vector) + .magnitude() + >= 0.5f32 + ); + } +} From f30001dd43bf67160dde95dbdc1fc95693fc14f4 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Fri, 27 Sep 2024 09:22:16 +0200 Subject: [PATCH 2/7] test for wrong self intersection after Collider::set_parent --- src/geometry/narrow_phase.rs | 136 ++++++++++++++++++++++++++++++++--- 1 file changed, 127 insertions(+), 9 deletions(-) diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index 4d2f944a..c0555401 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -1171,7 +1171,7 @@ impl NarrowPhase { #[cfg(test)] #[cfg(feature = "f32")] -//#[cfg(feature = "dim3")] +#[cfg(feature = "dim3")] mod test { use na::vector; @@ -1184,7 +1184,7 @@ mod test { /// Test for https://github.com/dimforge/rapier/issues/734. #[test] - pub fn reparent() { + pub fn collider_set_parent_depenetration() { let mut rigid_body_set = RigidBodySet::new(); let mut collider_set = ColliderSet::new(); @@ -1193,7 +1193,7 @@ mod test { /* Create body 1, which will contain both colliders at first. */ let rigid_body_1 = RigidBodyBuilder::dynamic() - .translation(vector![0.0, 10.0, 0.0]) + .translation(vector![0.0, 0.0, 0.0]) .build(); let body_1_handle = rigid_body_set.insert(rigid_body_1); @@ -1201,17 +1201,13 @@ mod test { let collider_1_handle = collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set); - /* Create collider 2. Parent it to rigid body 1. */ - //let collider_2_handle = - // collider_set.insert_with_parent(collider.build(), body_2_handle, &mut rigid_body_set); - /* Create collider 2. Parent it to rigid body 1. */ let collider_2_handle = collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set); /* Create body 2. No attached colliders yet. */ let rigid_body_2 = RigidBodyBuilder::dynamic() - .translation(vector![0.0, 10.0, 0.0]) + .translation(vector![0.0, 0.0, 0.0]) .build(); let body_2_handle = rigid_body_set.insert(rigid_body_2); @@ -1252,6 +1248,7 @@ mod test { < 0.5f32 ); + /* Parent collider 2 to body 2. */ collider_set.set_parent(collider_2_handle, Some(body_2_handle), &mut rigid_body_set); /* Run the game loop, stepping the simulation once per frame. */ @@ -1283,7 +1280,128 @@ mod test { assert!( (collider_1_position.translation.vector - collider_2_position.translation.vector) .magnitude() - >= 0.5f32 + >= 0.5f32, + "colliders should no longer be penetrating." + ); + } + + /// Test for https://github.com/dimforge/rapier/issues/734. + #[test] + pub fn collider_set_parent_no_self_intersection() { + let mut rigid_body_set = RigidBodySet::new(); + let mut collider_set = ColliderSet::new(); + + /* Create the ground. */ + let collider = ColliderBuilder::ball(0.5); + + /* Create body 1, which will contain collider 1. */ + let rigid_body_1 = RigidBodyBuilder::dynamic() + .translation(vector![0.0, 0.0, 0.0]) + .build(); + let body_1_handle = rigid_body_set.insert(rigid_body_1); + + /* Create collider 1. Parent it to rigid body 1. */ + let collider_1_handle = + collider_set.insert_with_parent(collider.build(), body_1_handle, &mut rigid_body_set); + + /* Create body 2, which will contain collider 2 at first. */ + let rigid_body_2 = RigidBodyBuilder::dynamic() + .translation(vector![0.0, 0.0, 0.0]) + .build(); + let body_2_handle = rigid_body_set.insert(rigid_body_2); + + /* Create collider 2. Parent it to rigid body 1. */ + //let collider_2_handle = + // collider_set.insert_with_parent(collider.build(), body_2_handle, &mut rigid_body_set); + + /* Create collider 2. Parent it to rigid body 1. */ + let collider_2_handle = + collider_set.insert_with_parent(collider.build(), body_2_handle, &mut rigid_body_set); + + /* Create other structures necessary for the simulation. */ + let gravity = vector![0.0, 0.0, 0.0]; + let integration_parameters = IntegrationParameters::default(); + let mut physics_pipeline = PhysicsPipeline::new(); + let mut island_manager = IslandManager::new(); + let mut broad_phase = DefaultBroadPhase::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 mut query_pipeline = QueryPipeline::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, + Some(&mut query_pipeline), + &physics_hooks, + &event_handler, + ); + let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos; + let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos; + assert!( + (collider_1_position.translation.vector - collider_2_position.translation.vector) + .magnitude() + < 0.5f32 + ); + + /* Parent collider 2 to body 1. */ + collider_set.set_parent(collider_2_handle, Some(body_1_handle), &mut rigid_body_set); + + /* Run the game loop, stepping the simulation once per frame. */ + for _ in 0..200 { + 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, + Some(&mut query_pipeline), + &physics_hooks, + &event_handler, + ); + + let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos; + let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos; + println!("collider 1 position: {}", collider_1_position.translation); + println!("collider 2 position: {}", collider_2_position.translation); + } + + let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos; + let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos; + assert!( + (collider_1_position.translation.vector - collider_2_position.translation.vector) + .magnitude() + < 0.5f32, + "colliders should be penetrating." + ); + assert!( + rigid_body_set + .get(body_1_handle) + .unwrap() + .position() + .translation + .vector + .magnitude() + // TODO: this is probably a way too big value to test, consider lowering it. + // In the meantime, this proves that current behaviour is incorrect. + < 30000f32, + "Body 1 should not have gone too far from origin." ); } } From aaa91d089e5f68da5ca59df39973c4b76ccb1559 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Fri, 18 Oct 2024 09:46:40 +0200 Subject: [PATCH 3/7] dynamics: remove new parent from contact and intersection graph ; maybe should be removed from graph_indices too? --- src/geometry/narrow_phase.rs | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index c0555401..55e3cb6d 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -458,12 +458,34 @@ impl NarrowPhase { } } } - + // Remove the new parent from the collision graphs + if co.changes.intersects(ColliderChanges::PARENT) { + let current_parent_body = co.parent(); + for inter in self + .contact_graph + .interactions_with(gid.contact_graph_index) + { + let Some(co2) = colliders.get(*handle) else { + continue; + }; + let other_parent_body = co2.parent(); + if other_parent_body == current_parent_body { + pairs_to_remove.push(( + ColliderPair::new(inter.0, inter.1), + PairRemovalMode::FromContactGraph, + )); + pairs_to_remove.push(( + ColliderPair::new(inter.0, inter.1), + PairRemovalMode::FromIntersectionGraph, + )); + } + } + } // For each collider which had their sensor status modified, we need // to transfer their contact/intersection graph edges to the intersection/contact graph. // To achieve this we will remove the relevant contact/intersection pairs form the // contact/intersection graphs, and then add them into the other graph. - if co.changes.contains(ColliderChanges::TYPE) { + if co.changes.intersects(ColliderChanges::TYPE) { if co.is_sensor() { // Find the contact pairs for this collider and // push them to `pairs_to_remove`. @@ -1250,7 +1272,13 @@ mod test { /* Parent collider 2 to body 2. */ collider_set.set_parent(collider_2_handle, Some(body_2_handle), &mut rigid_body_set); - + narrow_phase.add_pair( + &collider_set, + &ColliderPair { + collider1: collider_2_handle, + collider2: collider_1_handle, + }, + ); /* Run the game loop, stepping the simulation once per frame. */ for _ in 0..200 { physics_pipeline.step( From 32f2308942b884060ed45d1d6a6aac2151309b0f Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Mon, 16 Dec 2024 12:19:19 +0100 Subject: [PATCH 4/7] parent testing at the same place a interaction group check, to avoid missing parent change --- src/geometry/contact_pair.rs | 2 ++ src/geometry/narrow_phase.rs | 70 +++++++++++++++++++++++++----------- 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/src/geometry/contact_pair.rs b/src/geometry/contact_pair.rs index 3f569b20..52a9dc1a 100644 --- a/src/geometry/contact_pair.rs +++ b/src/geometry/contact_pair.rs @@ -82,6 +82,7 @@ impl IntersectionPair { events: &dyn EventHandler, ) { self.start_event_emitted = true; + println!("start"); events.handle_collision_event( bodies, colliders, @@ -99,6 +100,7 @@ impl IntersectionPair { events: &dyn EventHandler, ) { self.start_event_emitted = false; + println!("stop"); events.handle_collision_event( bodies, colliders, diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index 55e3cb6d..cb63396b 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -615,12 +615,6 @@ impl NarrowPhase { if let (Some(co1), Some(co2)) = (colliders.get(pair.collider1), colliders.get(pair.collider2)) { - if co1.parent.map(|p| p.handle) == co2.parent.map(|p| p.handle) && co1.parent.is_some() - { - // Same parents. Ignore collisions. - return; - } - // These colliders have no parents - continue. let (gid1, gid2) = self.graph_indices.ensure_pair_exists( @@ -745,7 +739,13 @@ impl NarrowPhase { // No update needed for these colliders. return; } - + if co1.parent.map(|p| p.handle) == co2.parent.map(|p| p.handle) + && co1.parent.is_some() + { + // Same parents. Ignore collisions. + edge.weight.intersecting = false; + break 'emit_events; + } // TODO: avoid lookup into bodies. let mut rb_type1 = RigidBodyType::Fixed; let mut rb_type2 = RigidBodyType::Fixed; @@ -846,6 +846,12 @@ impl NarrowPhase { // No update needed for these colliders. return; } + if co1.parent.map(|p| p.handle) == co2.parent.map(|p| p.handle) && co1.parent.is_some() + { + // Same parents. Ignore collisions. + pair.clear(); + break 'emit_events; + } let rb1 = co1.parent.map(|co_parent1| &bodies[co_parent1.handle]); let rb2 = co2.parent.map(|co_parent2| &bodies[co_parent2.handle]); @@ -1270,15 +1276,43 @@ mod test { < 0.5f32 ); + let contact_pair = narrow_phase + .contact_pair(collider_1_handle, collider_2_handle) + .expect("The contact pair should exist."); + assert_eq!(contact_pair.manifolds.len(), 0); + assert!(matches!( + narrow_phase.intersection_pair(collider_1_handle, collider_2_handle), + None, + )); /* Parent collider 2 to body 2. */ collider_set.set_parent(collider_2_handle, Some(body_2_handle), &mut rigid_body_set); - narrow_phase.add_pair( - &collider_set, - &ColliderPair { - collider1: collider_2_handle, - collider2: collider_1_handle, - }, + + 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, + Some(&mut query_pipeline), + &physics_hooks, + &event_handler, ); + + let contact_pair = narrow_phase + .contact_pair(collider_1_handle, collider_2_handle) + .expect("The contact pair should exist."); + assert_eq!(contact_pair.manifolds.len(), 1); + assert!(matches!( + narrow_phase.intersection_pair(collider_1_handle, collider_2_handle), + // FIXME: I believe this is expected because we've not enabled intersection detection? + None, + )); + /* Run the game loop, stepping the simulation once per frame. */ for _ in 0..200 { physics_pipeline.step( @@ -1305,6 +1339,7 @@ mod test { let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos; let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos; + println!("collider 2 position: {}", collider_2_position.translation); assert!( (collider_1_position.translation.vector - collider_2_position.translation.vector) .magnitude() @@ -1338,11 +1373,7 @@ mod test { .build(); let body_2_handle = rigid_body_set.insert(rigid_body_2); - /* Create collider 2. Parent it to rigid body 1. */ - //let collider_2_handle = - // collider_set.insert_with_parent(collider.build(), body_2_handle, &mut rigid_body_set); - - /* Create collider 2. Parent it to rigid body 1. */ + /* Create collider 2. Parent it to rigid body 2. */ let collider_2_handle = collider_set.insert_with_parent(collider.build(), body_2_handle, &mut rigid_body_set); @@ -1406,12 +1437,11 @@ mod test { let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos; let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos; - println!("collider 1 position: {}", collider_1_position.translation); - println!("collider 2 position: {}", collider_2_position.translation); } let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos; let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos; + println!("collider 2 position: {}", collider_2_position.translation); assert!( (collider_1_position.translation.vector - collider_2_position.translation.vector) .magnitude() From c0021be144c177ac7fd9294b7b0b4f6951d5c6c5 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Mon, 16 Dec 2024 14:16:56 +0100 Subject: [PATCH 5/7] add more asserts in test + more correct comments --- src/geometry/narrow_phase.rs | 47 ++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index cb63396b..fd8cfb4c 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -1282,6 +1282,7 @@ mod test { assert_eq!(contact_pair.manifolds.len(), 0); assert!(matches!( narrow_phase.intersection_pair(collider_1_handle, collider_2_handle), + // Interaction pair is for sensors None, )); /* Parent collider 2 to body 2. */ @@ -1309,7 +1310,7 @@ mod test { assert_eq!(contact_pair.manifolds.len(), 1); assert!(matches!( narrow_phase.intersection_pair(collider_1_handle, collider_2_handle), - // FIXME: I believe this is expected because we've not enabled intersection detection? + // Interaction pair is for sensors None, )); @@ -1406,6 +1407,16 @@ mod test { &physics_hooks, &event_handler, ); + + let contact_pair = narrow_phase + .contact_pair(collider_1_handle, collider_2_handle) + .expect("The contact pair should exist."); + assert_eq!( + contact_pair.manifolds.len(), + 1, + "There should be a contact manifold." + ); + let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos; let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos; assert!( @@ -1416,6 +1427,30 @@ mod test { /* Parent collider 2 to body 1. */ collider_set.set_parent(collider_2_handle, Some(body_1_handle), &mut rigid_body_set); + 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, + Some(&mut query_pipeline), + &physics_hooks, + &event_handler, + ); + + let contact_pair = narrow_phase + .contact_pair(collider_1_handle, collider_2_handle) + .expect("The contact pair should exist."); + assert_eq!( + contact_pair.manifolds.len(), + 0, + "Colliders with same parent should not be in contact together." + ); /* Run the game loop, stepping the simulation once per frame. */ for _ in 0..200 { @@ -1435,8 +1470,8 @@ mod test { &event_handler, ); - let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos; - let collider_2_position = collider_set.get(collider_2_handle).unwrap().pos; + collider_set.get(collider_1_handle).unwrap().pos; + collider_set.get(collider_2_handle).unwrap().pos; } let collider_1_position = collider_set.get(collider_1_handle).unwrap().pos; @@ -1445,7 +1480,7 @@ mod test { assert!( (collider_1_position.translation.vector - collider_2_position.translation.vector) .magnitude() - < 0.5f32, + < 0.1f32, "colliders should be penetrating." ); assert!( @@ -1456,9 +1491,7 @@ mod test { .translation .vector .magnitude() - // TODO: this is probably a way too big value to test, consider lowering it. - // In the meantime, this proves that current behaviour is incorrect. - < 30000f32, + < 0.1f32, "Body 1 should not have gone too far from origin." ); } From 41feb21bc1e0d397681dc831a7af4dd274584bb5 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Mon, 16 Dec 2024 14:21:54 +0100 Subject: [PATCH 6/7] add changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24369f91..30f4f365 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ - Fix `KinematicCharacterController::move_shape` not respecting parameters `max_slope_climb_angle` and `min_slope_slide_angle`. - Improve ground detection reliability for `KinematicCharacterController`. (#715) - Fix wasm32 default values for physics hooks filter to be consistent with native: `COMPUTE_IMPULSES`. +- Fix `set_parent` when ongoing collisions should be affected (#742): + - Fix collisions not being removed when a collider is parented to a rigidbody while in collision with it. + - Fix collisions not being added when the parent was removed while intersecting a (previously) sibling collider. ### Added From b00e486d5b313d7d1264f732c7423506feaff525 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Mon, 16 Dec 2024 14:28:50 +0100 Subject: [PATCH 7/7] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30f4f365..f7ab7c9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - Fix `KinematicCharacterController::move_shape` not respecting parameters `max_slope_climb_angle` and `min_slope_slide_angle`. - Improve ground detection reliability for `KinematicCharacterController`. (#715) - Fix wasm32 default values for physics hooks filter to be consistent with native: `COMPUTE_IMPULSES`. -- Fix `set_parent` when ongoing collisions should be affected (#742): +- Fix changing a collider parent when ongoing collisions should be affected (#742): - Fix collisions not being removed when a collider is parented to a rigidbody while in collision with it. - Fix collisions not being added when the parent was removed while intersecting a (previously) sibling collider.