diff options
Diffstat (limited to 'scene/2d/physics_body_2d.cpp')
-rw-r--r-- | scene/2d/physics_body_2d.cpp | 284 |
1 files changed, 190 insertions, 94 deletions
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index d52c293763..a9d4877cbb 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -102,21 +102,21 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::M } // Check depth of recovery. - real_t projected_length = r_result.motion.dot(motion_normal); - Vector2 recovery = r_result.motion - motion_normal * projected_length; + real_t projected_length = r_result.travel.dot(motion_normal); + Vector2 recovery = r_result.travel - motion_normal * projected_length; 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) { // Apply adjustment to motion. - r_result.motion = motion_normal * projected_length; - r_result.remainder = p_motion - r_result.motion; + r_result.travel = motion_normal * projected_length; + r_result.remainder = p_motion - r_result.travel; } } } if (!p_test_only) { - gt.elements[2] += r_result.motion; + gt.elements[2] += r_result.travel; set_global_transform(gt); } @@ -529,9 +529,9 @@ void RigidBody2D::_direct_state_changed(Object *p_state) { sleeping = state->is_sleeping(); emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed); } - if (get_script_instance()) { - get_script_instance()->call("_integrate_forces", state); - } + + GDVIRTUAL_CALL(_integrate_forces, state); + set_block_transform_notify(false); // want it back if (contact_monitor) { @@ -978,7 +978,7 @@ void RigidBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody2D::get_colliding_bodies); - BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState2D"))); + GDVIRTUAL_BIND(_integrate_forces, "state"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp"), "set_mass", "get_mass"); @@ -1043,14 +1043,14 @@ void RigidBody2D::_reload_physics_characteristics() { // So, if you pass 45 as limit, avoid numerical precision errors when angle is 45. #define FLOOR_ANGLE_THRESHOLD 0.01 -void CharacterBody2D::move_and_slide() { +bool CharacterBody2D::move_and_slide() { // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky. float delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); Vector2 current_platform_velocity = platform_velocity; if ((on_floor || on_wall) && platform_rid.is_valid()) { - bool excluded = (exclude_body_layers & platform_layer) != 0; + bool excluded = (moving_platform_ignore_layers & platform_layer) != 0; if (!excluded) { // This approach makes sure there is less delay between the actual body velocity and the one we saved. PhysicsDirectBodyState2D *bs = PhysicsServer2D::get_singleton()->body_get_direct_state(platform_rid); @@ -1081,10 +1081,24 @@ void CharacterBody2D::move_and_slide() { } } - Vector2 motion = linear_velocity * delta; + if (motion_mode == MOTION_MODE_GROUNDED) { + _move_and_slide_grounded(delta, was_on_floor, current_platform_velocity); + } else { + _move_and_slide_free(delta); + } + + if (!on_floor && !on_wall) { + // Add last platform velocity when just left a moving platform. + linear_velocity += current_platform_velocity; + } + + return motion_results.size() > 0; +} + +void CharacterBody2D::_move_and_slide_grounded(real_t p_delta, bool p_was_on_floor, const Vector2 &p_prev_platform_velocity) { + Vector2 motion = linear_velocity * p_delta; Vector2 motion_slide_up = motion.slide(up_direction); - Vector2 prev_platform_velocity = current_platform_velocity; Vector2 prev_floor_normal = floor_normal; RID prev_platform_rid = platform_rid; int prev_platform_layer = platform_layer; @@ -1095,7 +1109,7 @@ void CharacterBody2D::move_and_slide() { // No sliding on first attempt to keep floor motion stable when possible, // When stop on slope is enabled or when there is no up direction. - bool sliding_enabled = !stop_on_slope || up_direction == Vector2(); + 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; bool first_slide = true; @@ -1104,23 +1118,21 @@ void CharacterBody2D::move_and_slide() { for (int iteration = 0; iteration < max_slides; ++iteration) { PhysicsServer2D::MotionResult result; - bool found_collision = false; Vector2 prev_position = get_global_transform().elements[2]; bool collided = move_and_collide(motion, result, margin, false, !sliding_enabled); if (collided) { - found_collision = true; motion_results.push_back(result); _set_collision_direction(result); - if (on_floor && stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) { + if (on_floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) { Transform2D gt = get_global_transform(); - if (result.motion.length() > margin) { - gt.elements[2] -= result.motion.slide(up_direction); + if (result.travel.length() > margin) { + gt.elements[2] -= result.travel.slide(up_direction); } else { - gt.elements[2] -= result.motion; + gt.elements[2] -= result.travel; } set_global_transform(gt); linear_velocity = Vector2(); @@ -1134,28 +1146,27 @@ void CharacterBody2D::move_and_slide() { } // Move on floor only checks. - if (move_on_floor_only && on_wall && motion_slide_up.dot(result.collision_normal) <= 0) { - // Avoid to move forward on a wall if move_on_floor_only is true. - if (was_on_floor && !is_on_floor_only() && !vel_dir_facing_up) { + if (floor_block_on_wall && on_wall && motion_slide_up.dot(result.collision_normal) <= 0) { + // Avoid to move forward on a wall if floor_block_on_wall is true. + if (p_was_on_floor && !on_floor && !vel_dir_facing_up) { // If the movement is large the body can be prevented from reaching the walls. - if (result.motion.length() <= margin) { + if (result.travel.length() <= margin) { // Cancels the motion. Transform2D gt = get_global_transform(); - gt.elements[2] -= result.motion; + gt.elements[2] -= result.travel; set_global_transform(gt); } on_floor = true; platform_rid = prev_platform_rid; platform_layer = prev_platform_layer; - - platform_velocity = prev_platform_velocity; + platform_velocity = p_prev_platform_velocity; floor_normal = prev_floor_normal; linear_velocity = Vector2(); motion = Vector2(); break; } // Prevents the body from being able to climb a slope when it moves forward against the wall. - else if (!is_on_floor_only()) { + else if (!on_floor) { motion = up_direction * up_direction.dot(result.remainder); motion = motion.slide(result.collision_normal); } else { @@ -1163,12 +1174,10 @@ void CharacterBody2D::move_and_slide() { } } // Constant Speed when the slope is upward. - else if (constant_speed_on_floor && is_on_floor_only() && can_apply_constant_speed && was_on_floor && motion.dot(result.collision_normal) < 0) { + else if (floor_constant_speed && is_on_floor_only() && can_apply_constant_speed && p_was_on_floor && motion.dot(result.collision_normal) < 0) { can_apply_constant_speed = false; Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized(); - if (!motion_slide_norm.is_equal_approx(Vector2())) { - motion = motion_slide_norm * (motion_slide_up.length() - result.motion.slide(up_direction).length() - last_travel.slide(up_direction).length()); - } + 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)) { @@ -1197,11 +1206,11 @@ void CharacterBody2D::move_and_slide() { } } - last_travel = result.motion; + last_travel = result.travel; } // When you move forward in a downward slope you don’t collide because you will be in the air. // This test ensures that constant speed is applied, only if the player is still on the ground after the snap is applied. - else if (constant_speed_on_floor && first_slide && _on_floor_if_snapped(was_on_floor, vel_dir_facing_up)) { + else if (floor_constant_speed && first_slide && _on_floor_if_snapped(p_was_on_floor, vel_dir_facing_up)) { can_apply_constant_speed = false; sliding_enabled = true; Transform2D gt = get_global_transform(); @@ -1209,27 +1218,20 @@ void CharacterBody2D::move_and_slide() { set_global_transform(gt); Vector2 motion_slide_norm = motion.slide(prev_floor_normal).normalized(); - if (!motion_slide_norm.is_equal_approx(Vector2())) { - motion = motion_slide_norm * (motion_slide_up.length()); - found_collision = true; - } + motion = motion_slide_norm * (motion_slide_up.length()); + collided = true; } can_apply_constant_speed = !can_apply_constant_speed && !sliding_enabled; sliding_enabled = true; first_slide = false; - if (!found_collision || motion.is_equal_approx(Vector2())) { + if (!collided || motion.is_equal_approx(Vector2())) { break; } } - _snap_on_floor(was_on_floor, vel_dir_facing_up); - - if (!on_floor && !on_wall) { - // Add last platform velocity when just left a moving platform. - linear_velocity += current_platform_velocity; - } + _snap_on_floor(p_was_on_floor, vel_dir_facing_up); // Reset the gravity accumulation when touching the ground. if (on_floor && !vel_dir_facing_up) { @@ -1237,8 +1239,47 @@ void CharacterBody2D::move_and_slide() { } } +void CharacterBody2D::_move_and_slide_free(real_t p_delta) { + Vector2 motion = linear_velocity * p_delta; + + platform_rid = RID(); + floor_normal = Vector2(); + platform_velocity = Vector2(); + + bool first_slide = true; + for (int iteration = 0; iteration < max_slides; ++iteration) { + PhysicsServer2D::MotionResult result; + + bool collided = move_and_collide(motion, result, margin, false, false); + + if (collided) { + motion_results.push_back(result); + _set_collision_direction(result); + + if (free_mode_min_slide_angle != 0 && result.get_angle(-linear_velocity.normalized()) < free_mode_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { + motion = Vector2(); + } else if (first_slide) { + Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized(); + motion = motion_slide_norm * (motion.length() - result.travel.length()); + } else { + motion = result.remainder.slide(result.collision_normal); + } + + if (motion.dot(linear_velocity) <= 0.0) { + motion = Vector2(); + } + } + + first_slide = false; + + if (!collided || motion.is_equal_approx(Vector2())) { + break; + } + } +} + void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) { - if (Math::is_equal_approx(floor_snap_length, 0) || up_direction == Vector2() || on_floor || !was_on_floor || vel_dir_facing_up) { + if (Math::is_equal_approx(floor_snap_length, 0) || on_floor || !was_on_floor || vel_dir_facing_up) { return; } @@ -1246,20 +1287,19 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) PhysicsServer2D::MotionResult result; if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false)) { bool apply = true; - float collision_angle = Math::acos(result.collision_normal.dot(up_direction)); - if (collision_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { + if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { on_floor = true; floor_normal = result.collision_normal; platform_velocity = result.collider_velocity; _set_platform_data(result); - if (stop_on_slope) { + if (floor_stop_on_slope) { // move and collide may stray the object a bit because of pre un-stucking, // so only ensure that motion happens on floor direction in this case. - if (result.motion.length() > margin) { - result.motion = up_direction * up_direction.dot(result.motion); + if (result.travel.length() > margin) { + result.travel = up_direction * up_direction.dot(result.travel); } else { - result.motion = Vector2(); + result.travel = Vector2(); } } } else { @@ -1267,7 +1307,7 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) } if (apply) { - gt.elements[2] += result.motion; + gt.elements[2] += result.travel; set_global_transform(gt); } } @@ -1280,7 +1320,7 @@ bool CharacterBody2D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facin PhysicsServer2D::MotionResult result; if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false)) { - if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { + if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { return true; } } @@ -1289,16 +1329,12 @@ bool CharacterBody2D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facin } void CharacterBody2D::_set_collision_direction(const PhysicsServer2D::MotionResult &p_result) { - if (up_direction == Vector2()) { - return; - } - - if (Math::acos(p_result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor + if (motion_mode == MOTION_MODE_GROUNDED && p_result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor on_floor = true; floor_normal = p_result.collision_normal; platform_velocity = p_result.collider_velocity; _set_platform_data(p_result); - } else if (Math::acos(p_result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling + } else if (motion_mode == MOTION_MODE_GROUNDED && p_result.get_angle(-up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling on_ceiling = true; } else { on_wall = true; @@ -1352,11 +1388,16 @@ Vector2 CharacterBody2D::get_floor_normal() const { return floor_normal; } +real_t CharacterBody2D::get_floor_angle(const Vector2 &p_up_direction) const { + ERR_FAIL_COND_V(p_up_direction == Vector2(), 0); + return Math::acos(floor_normal.dot(p_up_direction)); +} + Vector2 CharacterBody2D::get_platform_velocity() const { return platform_velocity; } -int CharacterBody2D::get_slide_count() const { +int CharacterBody2D::get_slide_collision_count() const { return motion_results.size(); } @@ -1380,6 +1421,13 @@ Ref<KinematicCollision2D> CharacterBody2D::_get_slide_collision(int p_bounce) { return slide_colliders[p_bounce]; } +Ref<KinematicCollision2D> CharacterBody2D::_get_last_slide_collision() { + if (motion_results.size() == 0) { + return Ref<KinematicCollision2D>(); + } + return _get_slide_collision(motion_results.size() - 1); +} + void CharacterBody2D::set_safe_margin(real_t p_margin) { margin = p_margin; } @@ -1388,28 +1436,28 @@ real_t CharacterBody2D::get_safe_margin() const { return margin; } -bool CharacterBody2D::is_stop_on_slope_enabled() const { - return stop_on_slope; +bool CharacterBody2D::is_floor_stop_on_slope_enabled() const { + return floor_stop_on_slope; } -void CharacterBody2D::set_stop_on_slope_enabled(bool p_enabled) { - stop_on_slope = p_enabled; +void CharacterBody2D::set_floor_stop_on_slope_enabled(bool p_enabled) { + floor_stop_on_slope = p_enabled; } -bool CharacterBody2D::is_constant_speed_on_floor_enabled() const { - return constant_speed_on_floor; +bool CharacterBody2D::is_floor_constant_speed_enabled() const { + return floor_constant_speed; } -void CharacterBody2D::set_constant_speed_on_floor_enabled(bool p_enabled) { - constant_speed_on_floor = p_enabled; +void CharacterBody2D::set_floor_constant_speed_enabled(bool p_enabled) { + floor_constant_speed = p_enabled; } -bool CharacterBody2D::is_move_on_floor_only_enabled() const { - return move_on_floor_only; +bool CharacterBody2D::is_floor_block_on_wall_enabled() const { + return floor_block_on_wall; } -void CharacterBody2D::set_move_on_floor_only_enabled(bool p_enabled) { - move_on_floor_only = p_enabled; +void CharacterBody2D::set_floor_block_on_wall_enabled(bool p_enabled) { + floor_block_on_wall = p_enabled; } bool CharacterBody2D::is_slide_on_ceiling_enabled() const { @@ -1420,12 +1468,20 @@ void CharacterBody2D::set_slide_on_ceiling_enabled(bool p_enabled) { slide_on_ceiling = p_enabled; } -uint32_t CharacterBody2D::get_exclude_body_layers() const { - return exclude_body_layers; +uint32_t CharacterBody2D::get_moving_platform_ignore_layers() const { + return moving_platform_ignore_layers; } -void CharacterBody2D::set_exclude_body_layers(uint32_t p_exclude_layers) { - exclude_body_layers = p_exclude_layers; +void CharacterBody2D::set_moving_platform_ignore_layers(uint32_t p_exclude_layers) { + moving_platform_ignore_layers = p_exclude_layers; +} + +void CharacterBody2D::set_motion_mode(MotionMode p_mode) { + motion_mode = p_mode; +} + +CharacterBody2D::MotionMode CharacterBody2D::get_motion_mode() const { + return motion_mode; } int CharacterBody2D::get_max_slides() const { @@ -1454,11 +1510,20 @@ void CharacterBody2D::set_floor_snap_length(real_t p_floor_snap_length) { floor_snap_length = p_floor_snap_length; } +real_t CharacterBody2D::get_free_mode_min_slide_angle() const { + return free_mode_min_slide_angle; +} + +void CharacterBody2D::set_free_mode_min_slide_angle(real_t p_radians) { + free_mode_min_slide_angle = p_radians; +} + const Vector2 &CharacterBody2D::get_up_direction() const { return up_direction; } void CharacterBody2D::set_up_direction(const Vector2 &p_up_direction) { + ERR_FAIL_COND_MSG(p_up_direction == Vector2(), "up_direction can't be equal to Vector2.ZERO, consider using Free motion mode instead."); up_direction = p_up_direction.normalized(); } @@ -1484,17 +1549,17 @@ void CharacterBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody2D::set_safe_margin); ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody2D::get_safe_margin); - ClassDB::bind_method(D_METHOD("is_stop_on_slope_enabled"), &CharacterBody2D::is_stop_on_slope_enabled); - ClassDB::bind_method(D_METHOD("set_stop_on_slope_enabled", "enabled"), &CharacterBody2D::set_stop_on_slope_enabled); - ClassDB::bind_method(D_METHOD("set_constant_speed_on_floor_enabled", "enabled"), &CharacterBody2D::set_constant_speed_on_floor_enabled); - ClassDB::bind_method(D_METHOD("is_constant_speed_on_floor_enabled"), &CharacterBody2D::is_constant_speed_on_floor_enabled); - ClassDB::bind_method(D_METHOD("set_move_on_floor_only_enabled", "enabled"), &CharacterBody2D::set_move_on_floor_only_enabled); - ClassDB::bind_method(D_METHOD("is_move_on_floor_only_enabled"), &CharacterBody2D::is_move_on_floor_only_enabled); + ClassDB::bind_method(D_METHOD("is_floor_stop_on_slope_enabled"), &CharacterBody2D::is_floor_stop_on_slope_enabled); + ClassDB::bind_method(D_METHOD("set_floor_stop_on_slope_enabled", "enabled"), &CharacterBody2D::set_floor_stop_on_slope_enabled); + ClassDB::bind_method(D_METHOD("set_floor_constant_speed_enabled", "enabled"), &CharacterBody2D::set_floor_constant_speed_enabled); + ClassDB::bind_method(D_METHOD("is_floor_constant_speed_enabled"), &CharacterBody2D::is_floor_constant_speed_enabled); + ClassDB::bind_method(D_METHOD("set_floor_block_on_wall_enabled", "enabled"), &CharacterBody2D::set_floor_block_on_wall_enabled); + ClassDB::bind_method(D_METHOD("is_floor_block_on_wall_enabled"), &CharacterBody2D::is_floor_block_on_wall_enabled); ClassDB::bind_method(D_METHOD("set_slide_on_ceiling_enabled", "enabled"), &CharacterBody2D::set_slide_on_ceiling_enabled); ClassDB::bind_method(D_METHOD("is_slide_on_ceiling_enabled"), &CharacterBody2D::is_slide_on_ceiling_enabled); - ClassDB::bind_method(D_METHOD("set_exclude_body_layers", "exclude_layer"), &CharacterBody2D::set_exclude_body_layers); - ClassDB::bind_method(D_METHOD("get_exclude_body_layers"), &CharacterBody2D::get_exclude_body_layers); + ClassDB::bind_method(D_METHOD("set_moving_platform_ignore_layers", "exclude_layer"), &CharacterBody2D::set_moving_platform_ignore_layers); + ClassDB::bind_method(D_METHOD("get_moving_platform_ignore_layers"), &CharacterBody2D::get_moving_platform_ignore_layers); ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody2D::get_max_slides); ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody2D::set_max_slides); @@ -1502,8 +1567,12 @@ void CharacterBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody2D::set_floor_max_angle); ClassDB::bind_method(D_METHOD("get_floor_snap_length"), &CharacterBody2D::get_floor_snap_length); ClassDB::bind_method(D_METHOD("set_floor_snap_length", "floor_snap_length"), &CharacterBody2D::set_floor_snap_length); + ClassDB::bind_method(D_METHOD("get_free_mode_min_slide_angle"), &CharacterBody2D::get_free_mode_min_slide_angle); + ClassDB::bind_method(D_METHOD("set_free_mode_min_slide_angle", "radians"), &CharacterBody2D::set_free_mode_min_slide_angle); ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody2D::get_up_direction); ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody2D::set_up_direction); + ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody2D::set_motion_mode); + ClassDB::bind_method(D_METHOD("get_motion_mode"), &CharacterBody2D::get_motion_mode); ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody2D::is_on_floor); ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody2D::is_on_floor_only); @@ -1512,22 +1581,43 @@ void CharacterBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody2D::is_on_wall); ClassDB::bind_method(D_METHOD("is_on_wall_only"), &CharacterBody2D::is_on_wall_only); ClassDB::bind_method(D_METHOD("get_floor_normal"), &CharacterBody2D::get_floor_normal); + ClassDB::bind_method(D_METHOD("get_floor_angle", "up_direction"), &CharacterBody2D::get_floor_angle, DEFVAL(Vector2(0.0, -1.0))); ClassDB::bind_method(D_METHOD("get_platform_velocity"), &CharacterBody2D::get_platform_velocity); - ClassDB::bind_method(D_METHOD("get_slide_count"), &CharacterBody2D::get_slide_count); + ClassDB::bind_method(D_METHOD("get_slide_collision_count"), &CharacterBody2D::get_slide_collision_count); ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody2D::_get_slide_collision); + ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody2D::_get_last_slide_collision); + ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Free", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stop_on_slope"), "set_stop_on_slope_enabled", "is_stop_on_slope_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "constant_speed_on_floor"), "set_constant_speed_on_floor_enabled", "is_constant_speed_on_floor_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "move_on_floor_only"), "set_move_on_floor_only_enabled", "is_move_on_floor_only_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_RANGE, "1,8,1,or_greater"), "set_max_slides", "get_max_slides"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_slides", "get_max_slides"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction"); + ADD_GROUP("Free Mode", "free_mode_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "free_mode_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_free_mode_min_slide_angle", "get_free_mode_min_slide_angle"); + ADD_GROUP("Floor", "floor_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,1000,0.1"), "set_floor_snap_length", "get_floor_snap_length"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "exclude_body_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_exclude_body_layers", "get_exclude_body_layers"); - + ADD_GROUP("Moving platform", "moving_platform"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_ignore_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_ignore_layers", "get_moving_platform_ignore_layers"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); + + BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED); + BIND_ENUM_CONSTANT(MOTION_MODE_FREE); +} + +void CharacterBody2D::_validate_property(PropertyInfo &property) const { + if (motion_mode == MOTION_MODE_FREE) { + if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } + } else { + if (property.name == "free_mode_min_slide_angle") { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } + } } CharacterBody2D::CharacterBody2D() : @@ -1553,13 +1643,18 @@ Vector2 KinematicCollision2D::get_normal() const { } Vector2 KinematicCollision2D::get_travel() const { - return result.motion; + return result.travel; } Vector2 KinematicCollision2D::get_remainder() const { return result.remainder; } +real_t KinematicCollision2D::get_angle(const Vector2 &p_up_direction) const { + ERR_FAIL_COND_V(p_up_direction == Vector2(), 0); + return result.get_angle(p_up_direction); +} + Object *KinematicCollision2D::get_local_shape() const { if (!owner) { return nullptr; @@ -1614,6 +1709,7 @@ void KinematicCollision2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_normal"), &KinematicCollision2D::get_normal); ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision2D::get_travel); ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision2D::get_remainder); + ClassDB::bind_method(D_METHOD("get_angle", "up_direction"), &KinematicCollision2D::get_angle, DEFVAL(Vector2(0.0, -1.0))); ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision2D::get_local_shape); ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision2D::get_collider); ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision2D::get_collider_id); |