diff options
Diffstat (limited to 'scene/2d')
-rw-r--r-- | scene/2d/joint_2d.cpp (renamed from scene/2d/joints_2d.cpp) | 4 | ||||
-rw-r--r-- | scene/2d/joint_2d.h (renamed from scene/2d/joints_2d.h) | 8 | ||||
-rw-r--r-- | scene/2d/physical_bone_2d.cpp | 2 | ||||
-rw-r--r-- | scene/2d/physical_bone_2d.h | 4 | ||||
-rw-r--r-- | scene/2d/physics_body_2d.cpp | 100 | ||||
-rw-r--r-- | scene/2d/physics_body_2d.h | 6 |
6 files changed, 69 insertions, 55 deletions
diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joint_2d.cpp index 4a6606256e..3b371d4a07 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joint_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* joints_2d.cpp */ +/* joint_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "joints_2d.h" +#include "joint_2d.h" #include "physics_body_2d.h" #include "scene/scene_string_names.h" diff --git a/scene/2d/joints_2d.h b/scene/2d/joint_2d.h index dc5a08f815..0c3956e463 100644 --- a/scene/2d/joints_2d.h +++ b/scene/2d/joint_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* joints_2d.h */ +/* joint_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef JOINTS_2D_H -#define JOINTS_2D_H +#ifndef JOINT_2D_H +#define JOINT_2D_H #include "node_2d.h" @@ -148,4 +148,4 @@ public: DampedSpringJoint2D(); }; -#endif // JOINTS_2D_H +#endif // JOINT_2D_H diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp index 48817679bc..c1b0bc35dd 100644 --- a/scene/2d/physical_bone_2d.cpp +++ b/scene/2d/physical_bone_2d.cpp @@ -30,6 +30,8 @@ #include "physical_bone_2d.h" +#include "scene/2d/joint_2d.h" + void PhysicalBone2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { diff --git a/scene/2d/physical_bone_2d.h b/scene/2d/physical_bone_2d.h index a250d0aadd..8b41f75c3e 100644 --- a/scene/2d/physical_bone_2d.h +++ b/scene/2d/physical_bone_2d.h @@ -31,11 +31,11 @@ #ifndef PHYSICAL_BONE_2D_H #define PHYSICAL_BONE_2D_H -#include "scene/2d/joints_2d.h" #include "scene/2d/physics_body_2d.h" - #include "scene/2d/skeleton_2d.h" +class Joint2D; + class PhysicalBone2D : public RigidDynamicBody2D { GDCLASS(PhysicalBone2D, RigidDynamicBody2D); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 3c25f99ada..9a10255acc 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -54,13 +54,14 @@ PhysicsBody2D::~PhysicsBody2D() { } } -Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_test_only, real_t p_margin) { - PhysicsServer2D::MotionResult result; - +Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_linear_velocity, bool p_test_only, real_t p_margin) { // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky. double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); - if (move_and_collide(p_motion * delta, result, p_margin, p_test_only)) { + PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_linear_velocity * delta, p_margin); + + PhysicsServer2D::MotionResult result; + if (move_and_collide(parameters, result, p_test_only)) { // Create a new instance when the cached reference is invalid or still in use in script. if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) { motion_cache.instantiate(); @@ -74,18 +75,18 @@ Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_t return Ref<KinematicCollision2D>(); } -bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_test_only, bool p_cancel_sliding, bool p_collide_separation_ray, const Set<RID> &p_exclude) { +bool PhysicsBody2D::move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only, bool p_cancel_sliding) { if (is_only_update_transform_changes_enabled()) { ERR_PRINT("Move functions do not work together with 'sync to physics' option. Please read the documentation."); } - Transform2D gt = get_global_transform(); - bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_margin, &r_result, p_collide_separation_ray, p_exclude); + + bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_parameters, &r_result); // Restore direction of motion to be along original motion, // in order to avoid sliding due to recovery, // but only if collision depth is low enough to avoid tunneling. if (p_cancel_sliding) { - real_t motion_length = p_motion.length(); + real_t motion_length = p_parameters.motion.length(); real_t precision = 0.001; if (colliding) { @@ -93,7 +94,7 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::M // so even in normal resting cases the depth can be a bit more than the margin. precision += motion_length * (r_result.collision_unsafe_fraction - r_result.collision_safe_fraction); - if (r_result.collision_depth > (real_t)p_margin + precision) { + if (r_result.collision_depth > p_parameters.margin + precision) { p_cancel_sliding = false; } } @@ -102,7 +103,7 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::M // When motion is null, recovery is the resulting motion. Vector2 motion_normal; if (motion_length > CMP_EPSILON) { - motion_normal = p_motion / motion_length; + motion_normal = p_parameters.motion / motion_length; } // Check depth of recovery. @@ -111,15 +112,16 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::M real_t recovery_length = recovery.length(); // Fixes cases where canceling slide causes the motion to go too deep into the ground, // because we're only taking rest information into account and not general recovery. - if (recovery_length < (real_t)p_margin + precision) { + if (recovery_length < p_parameters.margin + precision) { // Apply adjustment to motion. r_result.travel = motion_normal * projected_length; - r_result.remainder = p_motion - r_result.travel; + r_result.remainder = p_parameters.motion - r_result.travel; } } } if (!p_test_only) { + Transform2D gt = p_parameters.from; gt.elements[2] += r_result.travel; set_global_transform(gt); } @@ -127,7 +129,7 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::M return colliding; } -bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) { +bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_linear_velocity, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) { ERR_FAIL_COND_V(!is_inside_tree(), false); PhysicsServer2D::MotionResult *r = nullptr; @@ -139,7 +141,9 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky. double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); - return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion * delta, p_margin, r); + PhysicsServer2D::MotionParameters parameters(p_from, p_linear_velocity * delta, p_margin); + + return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r); } TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() { @@ -1083,10 +1087,11 @@ bool CharacterBody2D::move_and_slide() { on_wall = false; 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); + PhysicsServer2D::MotionResult floor_result; - Set<RID> exclude; - exclude.insert(platform_rid); - if (move_and_collide(current_platform_velocity * delta, floor_result, margin, false, false, false, exclude)) { + if (move_and_collide(parameters, floor_result, false, false)) { motion_results.push_back(floor_result); _set_collision_direction(floor_result); } @@ -1131,22 +1136,39 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo bool sliding_enabled = !floor_stop_on_slope; // Constant speed can be applied only the first time sliding is enabled. bool can_apply_constant_speed = sliding_enabled; + // If the platform's ceiling push down the body. + bool apply_ceiling_velocity = false; bool first_slide = true; bool vel_dir_facing_up = motion_velocity.dot(up_direction) > 0; Vector2 last_travel; for (int iteration = 0; iteration < max_slides; ++iteration) { - PhysicsServer2D::MotionResult result; + PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin); - Vector2 prev_position = get_global_transform().elements[2]; + Vector2 prev_position = parameters.from.elements[2]; + + PhysicsServer2D::MotionResult result; + bool collided = move_and_collide(parameters, result, false, !sliding_enabled); - bool collided = move_and_collide(motion, result, margin, false, !sliding_enabled); last_motion = result.travel; if (collided) { motion_results.push_back(result); _set_collision_direction(result); + // If we hit a ceiling platform, we set the vertical motion_velocity to at least the platform one. + if (on_ceiling && result.collider_velocity != Vector2() && result.collider_velocity.dot(up_direction) < 0) { + // If ceiling sliding is on, only apply when the ceiling is flat or when the motion is upward. + if (!slide_on_ceiling || motion.dot(up_direction) < 0 || (result.collision_normal + up_direction).length() < 0.01) { + apply_ceiling_velocity = true; + Vector2 ceiling_vertical_velocity = up_direction * up_direction.dot(result.collider_velocity); + Vector2 motion_vertical_velocity = up_direction * up_direction.dot(motion_velocity); + if (motion_vertical_velocity.dot(up_direction) > 0 || ceiling_vertical_velocity.length_squared() > motion_vertical_velocity.length_squared()) { + motion_velocity = ceiling_vertical_velocity + motion_velocity.slide(up_direction); + } + } + } + if (on_floor && floor_stop_on_slope && (motion_velocity.normalized() + up_direction).length() < 0.01) { Transform2D gt = get_global_transform(); if (result.travel.length() <= margin + CMP_EPSILON) { @@ -1200,7 +1222,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo motion = motion_slide_norm * (motion_slide_up.length() - result.travel.slide(up_direction).length() - last_travel.slide(up_direction).length()); } // Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling. - else if ((sliding_enabled || !on_floor) && (!on_ceiling || slide_on_ceiling || !vel_dir_facing_up)) { + else if ((sliding_enabled || !on_floor) && (!on_ceiling || slide_on_ceiling || !vel_dir_facing_up) && !apply_ceiling_velocity) { Vector2 slide_motion = result.remainder.slide(result.collision_normal); if (slide_motion.dot(motion_velocity) > 0.0) { motion = slide_motion; @@ -1268,9 +1290,11 @@ void CharacterBody2D::_move_and_slide_free(double p_delta) { bool first_slide = true; for (int iteration = 0; iteration < max_slides; ++iteration) { + PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin); + PhysicsServer2D::MotionResult result; + bool collided = move_and_collide(parameters, result, false, false); - bool collided = move_and_collide(motion, result, margin, false, false); last_motion = result.travel; if (collided) { @@ -1312,10 +1336,11 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) // Snap by at least collision margin to keep floor state consistent. real_t length = MAX(floor_snap_length, margin); - Transform2D gt = get_global_transform(); + PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); + parameters.collide_separation_ray = true; + PhysicsServer2D::MotionResult result; - if (move_and_collide(-up_direction * length, result, margin, true, false, true)) { - bool apply = true; + if (move_and_collide(parameters, result, true, false)) { if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { on_floor = true; floor_normal = result.collision_normal; @@ -1330,13 +1355,9 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) result.travel = Vector2(); } } - } else { - apply = false; - } - if (apply) { - gt.elements[2] += result.travel; - set_global_transform(gt); + parameters.from.elements[2] += result.travel; + set_global_transform(parameters.from); } } } @@ -1349,8 +1370,11 @@ bool CharacterBody2D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facin // Snap by at least collision margin to keep floor state consistent. real_t length = MAX(floor_snap_length, margin); + PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); + parameters.collide_separation_ray = true; + PhysicsServer2D::MotionResult result; - if (move_and_collide(-up_direction * length, result, margin, true, false, true)) { + if (move_and_collide(parameters, result, true, false)) { if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { return true; } @@ -1791,16 +1815,4 @@ void KinematicCollision2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicCollision2D::get_collider_shape); ClassDB::bind_method(D_METHOD("get_collider_shape_index"), &KinematicCollision2D::get_collider_shape_index); ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicCollision2D::get_collider_velocity); - - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "", "get_position"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "normal"), "", "get_normal"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "travel"), "", "get_travel"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "remainder"), "", "get_remainder"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "local_shape"), "", "get_local_shape"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id"), "", "get_collider_id"); - ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_collider_rid"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider_shape"), "", "get_collider_shape"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape_index"), "", "get_collider_shape_index"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collider_velocity"), "", "get_collider_velocity"); } diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 70cc5cd9bf..fd8bb66158 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -47,11 +47,11 @@ protected: Ref<KinematicCollision2D> motion_cache; - Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_test_only = false, real_t p_margin = 0.08); + Ref<KinematicCollision2D> _move(const Vector2 &p_linear_velocity, bool p_test_only = false, real_t p_margin = 0.08); public: - bool move_and_collide(const Vector2 &p_motion, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_test_only = false, bool p_cancel_sliding = true, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()); - bool test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08); + bool move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); + bool test_move(const Transform2D &p_from, const Vector2 &p_linear_velocity, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08); TypedArray<PhysicsBody2D> get_collision_exceptions(); void add_collision_exception_with(Node *p_node); //must be physicsbody |