From 4f8d761be632a9d342655aa88a0745465b2177b8 Mon Sep 17 00:00:00 2001 From: PouleyKetchoupp Date: Thu, 30 Sep 2021 11:05:30 -0700 Subject: [PATCH] Fix physics glitch with TileMap moving platforms Added a parameter in test_body_motion to exclude attached objects from collision, used to avoid collision with all TileMap tiles with moving platform motion instead of just the one tile the character touches. Same changes made in 3D for consistency, and handling potential similar cases. --- doc/classes/PhysicsTestMotionParameters2D.xml | 3 +++ doc/classes/PhysicsTestMotionParameters3D.xml | 3 +++ scene/2d/physics_body_2d.cpp | 9 +++++++ scene/2d/physics_body_2d.h | 1 + scene/3d/physics_body_3d.cpp | 7 ++++++ scene/3d/physics_body_3d.h | 1 + servers/physics_2d/space_2d_sw.cpp | 9 +++++++ servers/physics_3d/space_3d_sw.cpp | 10 ++++++++ servers/physics_server_2d.cpp | 24 +++++++++++++++++++ servers/physics_server_2d.h | 4 ++++ servers/physics_server_3d.cpp | 24 +++++++++++++++++++ servers/physics_server_3d.h | 4 ++++ 12 files changed, 99 insertions(+) diff --git a/doc/classes/PhysicsTestMotionParameters2D.xml b/doc/classes/PhysicsTestMotionParameters2D.xml index 7cea8480390..46c1827b970 100644 --- a/doc/classes/PhysicsTestMotionParameters2D.xml +++ b/doc/classes/PhysicsTestMotionParameters2D.xml @@ -16,6 +16,9 @@ Optional array of body [RID] to exclude from collision. + + Optional array of object unique instance ID to exclude from collision. See [method Object.get_instance_id]. + Transform in global space where the motion should start. Usually set to [member Node2D.global_transform] for the current body's transform. diff --git a/doc/classes/PhysicsTestMotionParameters3D.xml b/doc/classes/PhysicsTestMotionParameters3D.xml index 07abbb1cb1e..d66aee3ae64 100644 --- a/doc/classes/PhysicsTestMotionParameters3D.xml +++ b/doc/classes/PhysicsTestMotionParameters3D.xml @@ -16,6 +16,9 @@ Optional array of body [RID] to exclude from collision. + + Optional array of object unique instance ID to exclude from collision. See [method Object.get_instance_id]. + Transform in global space where the motion should start. Usually set to [member Node3D.global_transform] for the current body's transform. diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 9a10255acc2..f493d97ceb1 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1089,6 +1089,9 @@ bool CharacterBody2D::move_and_slide() { if (!current_platform_velocity.is_equal_approx(Vector2())) { PhysicsServer2D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin); parameters.exclude_bodies.insert(platform_rid); + if (platform_object_id.is_valid()) { + parameters.exclude_objects.insert(platform_object_id); + } PhysicsServer2D::MotionResult floor_result; if (move_and_collide(parameters, floor_result, false, false)) { @@ -1125,9 +1128,11 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo Vector2 prev_floor_normal = floor_normal; RID prev_platform_rid = platform_rid; + ObjectID prev_platform_object_id = platform_object_id; int prev_platform_layer = platform_layer; platform_rid = RID(); + platform_object_id = ObjectID(); floor_normal = Vector2(); platform_velocity = Vector2(); @@ -1199,6 +1204,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo } on_floor = true; platform_rid = prev_platform_rid; + platform_object_id = prev_platform_object_id; platform_layer = prev_platform_layer; platform_velocity = p_prev_platform_velocity; floor_normal = prev_floor_normal; @@ -1285,6 +1291,7 @@ void CharacterBody2D::_move_and_slide_free(double p_delta) { Vector2 motion = motion_velocity * p_delta; platform_rid = RID(); + platform_object_id = ObjectID(); floor_normal = Vector2(); platform_velocity = Vector2(); @@ -1402,6 +1409,7 @@ void CharacterBody2D::_set_collision_direction(const PhysicsServer2D::MotionResu void CharacterBody2D::_set_platform_data(const PhysicsServer2D::MotionResult &p_result) { platform_rid = p_result.collider; + platform_object_id = p_result.collider_id; platform_velocity = p_result.collider_velocity; platform_layer = PhysicsServer2D::get_singleton()->body_get_collision_layer(platform_rid); } @@ -1620,6 +1628,7 @@ void CharacterBody2D::_notification(int p_what) { // Reset move_and_slide() data. on_floor = false; platform_rid = RID(); + platform_object_id = ObjectID(); on_ceiling = false; on_wall = false; motion_results.clear(); diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index fd8bb66158b..d1f52b33f25 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -368,6 +368,7 @@ private: Vector2 real_velocity; RID platform_rid; + ObjectID platform_object_id; bool on_floor = false; bool on_ceiling = false; bool on_wall = false; diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index b7c808398c5..976bff4fbce 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -1131,6 +1131,9 @@ bool CharacterBody3D::move_and_slide() { if (!current_platform_velocity.is_equal_approx(Vector3())) { PhysicsServer3D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin); parameters.exclude_bodies.insert(platform_rid); + if (platform_object_id.is_valid()) { + parameters.exclude_objects.insert(platform_object_id); + } PhysicsServer3D::MotionResult floor_result; if (move_and_collide(parameters, floor_result, false, false)) { @@ -1169,6 +1172,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo Vector3 prev_floor_normal = floor_normal; platform_rid = RID(); + platform_object_id = ObjectID(); platform_velocity = Vector3(); platform_ceiling_velocity = Vector3(); floor_normal = Vector3(); @@ -1416,6 +1420,7 @@ void CharacterBody3D::_move_and_slide_free(double p_delta) { Vector3 motion = motion_velocity * p_delta; platform_rid = RID(); + platform_object_id = ObjectID(); floor_normal = Vector3(); platform_velocity = Vector3(); @@ -1611,6 +1616,7 @@ void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResu void CharacterBody3D::_set_platform_data(const PhysicsServer3D::MotionCollision &p_collision) { platform_rid = p_collision.collider; + platform_object_id = p_collision.collider_id; platform_velocity = p_collision.collider_velocity; platform_layer = PhysicsServer3D::get_singleton()->body_get_collision_layer(platform_rid); } @@ -1833,6 +1839,7 @@ void CharacterBody3D::_notification(int p_what) { // Reset move_and_slide() data. collision_state.state = 0; platform_rid = RID(); + platform_object_id = ObjectID(); motion_results.clear(); platform_velocity = Vector3(); } break; diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index d2754e77261..5677df730c5 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -383,6 +383,7 @@ private: int max_slides = 6; int platform_layer = 0; RID platform_rid; + ObjectID platform_object_id; uint32_t moving_platform_floor_layers = UINT32_MAX; uint32_t moving_platform_wall_layers = 0; real_t floor_snap_length = 0.1; diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 5e25d7f7c4e..dd0780b5ff6 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -615,6 +615,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const PhysicsServer2D::Motion if (p_parameters.exclude_bodies.has(col_obj->get_self())) { continue; } + if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) { + continue; + } int shape_idx = intersection_query_subindex_results[i]; @@ -747,6 +750,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const PhysicsServer2D::Motion if (p_parameters.exclude_bodies.has(col_obj->get_self())) { continue; } + if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) { + continue; + } int col_shape_idx = intersection_query_subindex_results[i]; Shape2DSW *against_shape = col_obj->get_shape(col_shape_idx); @@ -896,6 +902,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const PhysicsServer2D::Motion if (p_parameters.exclude_bodies.has(col_obj->get_self())) { continue; } + if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) { + continue; + } int shape_idx = intersection_query_subindex_results[i]; diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp index f5f497e1670..c88747c0172 100644 --- a/servers/physics_3d/space_3d_sw.cpp +++ b/servers/physics_3d/space_3d_sw.cpp @@ -704,6 +704,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const PhysicsServer3D::Motion if (p_parameters.exclude_bodies.has(col_obj->get_self())) { continue; } + if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) { + continue; + } int shape_idx = intersection_query_subindex_results[i]; @@ -795,6 +798,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const PhysicsServer3D::Motion if (p_parameters.exclude_bodies.has(col_obj->get_self())) { continue; } + if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) { + continue; + } int shape_idx = intersection_query_subindex_results[i]; @@ -916,6 +922,10 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const PhysicsServer3D::Motion if (p_parameters.exclude_bodies.has(col_obj->get_self())) { continue; } + if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) { + continue; + } + int shape_idx = intersection_query_subindex_results[i]; rcd.object = col_obj; diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index ad53f9ed201..fe2970912a9 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -430,6 +430,26 @@ void PhysicsTestMotionParameters2D::set_exclude_bodies(const Vector &p_excl } } +Array PhysicsTestMotionParameters2D::get_exclude_objects() const { + Array exclude; + exclude.resize(parameters.exclude_objects.size()); + + int object_index = 0; + for (ObjectID object_id : parameters.exclude_objects) { + exclude[object_index++] = object_id; + } + + return exclude; +} + +void PhysicsTestMotionParameters2D::set_exclude_objects(const Array &p_exclude) { + for (int i = 0; i < p_exclude.size(); ++i) { + ObjectID object_id = p_exclude[i]; + ERR_CONTINUE(object_id.is_null()); + parameters.exclude_objects.insert(object_id); + } +} + void PhysicsTestMotionParameters2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_from"), &PhysicsTestMotionParameters2D::get_from); ClassDB::bind_method(D_METHOD("set_from"), &PhysicsTestMotionParameters2D::set_from); @@ -446,11 +466,15 @@ void PhysicsTestMotionParameters2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_exclude_bodies"), &PhysicsTestMotionParameters2D::get_exclude_bodies); ClassDB::bind_method(D_METHOD("set_exclude_bodies"), &PhysicsTestMotionParameters2D::set_exclude_bodies); + ClassDB::bind_method(D_METHOD("get_exclude_objects"), &PhysicsTestMotionParameters2D::get_exclude_objects); + ClassDB::bind_method(D_METHOD("set_exclude_objects"), &PhysicsTestMotionParameters2D::set_exclude_objects); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "from"), "set_from", "get_from"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "set_motion", "get_motion"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin"), "set_margin", "get_margin"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_separation_ray"), "set_collide_separation_ray_enabled", "is_collide_separation_ray_enabled"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude_bodies"), "set_exclude_bodies", "get_exclude_bodies"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude_objects"), "set_exclude_objects", "get_exclude_objects"); } /////////////////////////////// diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index 1028be05b74..26e14111112 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -472,6 +472,7 @@ public: real_t margin = 0.08; bool collide_separation_ray = false; Set exclude_bodies; + Set exclude_objects; MotionParameters() {} @@ -609,6 +610,9 @@ public: Vector get_exclude_bodies() const; void set_exclude_bodies(const Vector &p_exclude); + + Array get_exclude_objects() const; + void set_exclude_objects(const Array &p_exclude); }; class PhysicsTestMotionResult2D : public RefCounted { diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index 1b47eba134d..d66a8bfe0d4 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -380,6 +380,26 @@ void PhysicsTestMotionParameters3D::set_exclude_bodies(const Vector &p_excl } } +Array PhysicsTestMotionParameters3D::get_exclude_objects() const { + Array exclude; + exclude.resize(parameters.exclude_objects.size()); + + int object_index = 0; + for (ObjectID object_id : parameters.exclude_objects) { + exclude[object_index++] = object_id; + } + + return exclude; +} + +void PhysicsTestMotionParameters3D::set_exclude_objects(const Array &p_exclude) { + for (int i = 0; i < p_exclude.size(); ++i) { + ObjectID object_id = p_exclude[i]; + ERR_CONTINUE(object_id.is_null()); + parameters.exclude_objects.insert(object_id); + } +} + void PhysicsTestMotionParameters3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_from"), &PhysicsTestMotionParameters3D::get_from); ClassDB::bind_method(D_METHOD("set_from"), &PhysicsTestMotionParameters3D::set_from); @@ -399,12 +419,16 @@ void PhysicsTestMotionParameters3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_exclude_bodies"), &PhysicsTestMotionParameters3D::get_exclude_bodies); ClassDB::bind_method(D_METHOD("set_exclude_bodies"), &PhysicsTestMotionParameters3D::set_exclude_bodies); + ClassDB::bind_method(D_METHOD("get_exclude_objects"), &PhysicsTestMotionParameters3D::get_exclude_objects); + ClassDB::bind_method(D_METHOD("set_exclude_objects"), &PhysicsTestMotionParameters3D::set_exclude_objects); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "from"), "set_from", "get_from"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion"), "set_motion", "get_motion"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin"), "set_margin", "get_margin"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_collisions"), "set_max_collisions", "get_max_collisions"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_separation_ray"), "set_collide_separation_ray_enabled", "is_collide_separation_ray_enabled"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude_bodies"), "set_exclude_bodies", "get_exclude_bodies"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude_objects"), "set_exclude_objects", "get_exclude_objects"); } /////////////////////////////// diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 3d884de0957..c609afc11ee 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -491,6 +491,7 @@ public: int max_collisions = 1; bool collide_separation_ray = false; Set exclude_bodies; + Set exclude_objects; MotionParameters() {} @@ -805,6 +806,9 @@ public: Vector get_exclude_bodies() const; void set_exclude_bodies(const Vector &p_exclude); + + Array get_exclude_objects() const; + void set_exclude_objects(const Array &p_exclude); }; class PhysicsTestMotionResult3D : public RefCounted {