summaryrefslogtreecommitdiff
path: root/scene/2d/physics_body_2d.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/2d/physics_body_2d.cpp')
-rw-r--r--scene/2d/physics_body_2d.cpp430
1 files changed, 278 insertions, 152 deletions
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 9b4da2a77a..d52c293763 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -30,17 +30,12 @@
#include "physics_body_2d.h"
-#include "core/config/engine.h"
#include "core/core_string_names.h"
-#include "core/math/math_funcs.h"
-#include "core/object/class_db.h"
-#include "core/templates/list.h"
-#include "core/templates/rid.h"
#include "scene/scene_string_names.h"
void PhysicsBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false), DEFVAL(0.08));
- ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(true), DEFVAL(true), DEFVAL(Variant()), DEFVAL(0.08));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08));
+ ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08));
ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with);
@@ -59,29 +54,28 @@ PhysicsBody2D::~PhysicsBody2D() {
}
}
-Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only, real_t p_margin) {
+Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_test_only, real_t p_margin) {
PhysicsServer2D::MotionResult result;
- if (move_and_collide(p_motion, p_infinite_inertia, result, p_margin, p_exclude_raycast_shapes, p_test_only)) {
+ if (move_and_collide(p_motion, result, p_margin, p_test_only)) {
if (motion_cache.is_null()) {
motion_cache.instantiate();
motion_cache->owner = this;
}
motion_cache->result = result;
-
return motion_cache;
}
return Ref<KinematicCollision2D>();
}
-bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding, const Set<RID> &p_exclude) {
+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, const Set<RID> &p_exclude) {
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_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes, p_exclude);
+ bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_margin, &r_result, p_exclude);
// Restore direction of motion to be along original motion,
// in order to avoid sliding due to recovery,
@@ -129,7 +123,7 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_in
return colliding;
}
-bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) {
+bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
PhysicsServer2D::MotionResult *r = nullptr;
@@ -138,7 +132,7 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion
r = const_cast<PhysicsServer2D::MotionResult *>(&r_collision->result);
}
- return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes);
+ return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_margin, r);
}
TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() {
@@ -1046,137 +1040,230 @@ void RigidBody2D::_reload_physics_characteristics() {
//////////////////////////
-//so, if you pass 45 as limit, avoid numerical precision errors when angle is 45.
+// 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() {
- Vector2 body_velocity_normal = linear_velocity.normalized();
- bool was_on_floor = on_floor;
-
- // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
+ // 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_floor_velocity = floor_velocity;
-
- if ((on_floor || on_wall) && on_floor_body.is_valid()) {
- //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(on_floor_body);
- if (bs) {
- current_floor_velocity = bs->get_linear_velocity();
+ Vector2 current_platform_velocity = platform_velocity;
+
+ if ((on_floor || on_wall) && platform_rid.is_valid()) {
+ bool excluded = (exclude_body_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);
+ if (bs) {
+ Transform2D gt = get_global_transform();
+ Vector2 local_position = gt.elements[2] - bs->get_transform().elements[2];
+ current_platform_velocity = bs->get_velocity_at_local_position(local_position);
+ }
+ } else {
+ current_platform_velocity = Vector2();
}
}
motion_results.clear();
+
+ bool was_on_floor = on_floor;
on_floor = false;
on_ceiling = false;
on_wall = false;
- floor_normal = Vector2();
- floor_velocity = Vector2();
- if (current_floor_velocity != Vector2()) {
+ if (!current_platform_velocity.is_equal_approx(Vector2())) {
PhysicsServer2D::MotionResult floor_result;
Set<RID> exclude;
- exclude.insert(on_floor_body);
- if (move_and_collide(current_floor_velocity * delta, infinite_inertia, floor_result, true, false, false, false, exclude)) {
+ exclude.insert(platform_rid);
+ if (move_and_collide(current_platform_velocity * delta, floor_result, margin, false, false, exclude)) {
motion_results.push_back(floor_result);
_set_collision_direction(floor_result);
}
}
- on_floor_body = RID();
Vector2 motion = linear_velocity * 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;
+
+ platform_rid = RID();
+ floor_normal = Vector2();
+ platform_velocity = Vector2();
// No sliding on first attempt to keep floor motion stable when possible,
- // when stop on slope is enabled.
- bool sliding_enabled = !stop_on_slope;
+ // When stop on slope is enabled or when there is no up direction.
+ bool sliding_enabled = !stop_on_slope || up_direction == Vector2();
+ // Constant speed can be applied only the first time sliding is enabled.
+ bool can_apply_constant_speed = sliding_enabled;
+ bool first_slide = true;
+ bool vel_dir_facing_up = linear_velocity.dot(up_direction) > 0;
+ Vector2 last_travel;
for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer2D::MotionResult result;
bool found_collision = false;
- for (int i = 0; i < 2; ++i) {
- bool collided;
- if (i == 0) { //collide
- collided = move_and_collide(motion, infinite_inertia, result, margin, true, false, !sliding_enabled);
- if (!collided) {
- motion = Vector2(); //clear because no collision happened and motion completed
- }
- } else { //separate raycasts (if any)
- collided = separate_raycast_shapes(result);
- if (collided) {
- result.remainder = motion; //keep
- result.motion = Vector2();
+ 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) {
+ Transform2D gt = get_global_transform();
+ if (result.motion.length() > margin) {
+ gt.elements[2] -= result.motion.slide(up_direction);
+ } else {
+ gt.elements[2] -= result.motion;
}
+ set_global_transform(gt);
+ linear_velocity = Vector2();
+ motion = Vector2();
+ break;
}
- if (collided) {
- found_collision = true;
-
- motion_results.push_back(result);
- _set_collision_direction(result);
+ if (result.remainder.is_equal_approx(Vector2())) {
+ motion = Vector2();
+ break;
+ }
- if (on_floor && stop_on_slope) {
- if ((body_velocity_normal + up_direction).length() < 0.01) {
+ // 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 the movement is large the body can be prevented from reaching the walls.
+ if (result.motion.length() <= margin) {
+ // Cancels the motion.
Transform2D gt = get_global_transform();
- if (result.motion.length() > margin) {
- gt.elements[2] -= result.motion.slide(up_direction);
- } else {
- gt.elements[2] -= result.motion;
- }
+ gt.elements[2] -= result.motion;
set_global_transform(gt);
- linear_velocity = Vector2();
- return;
}
+ on_floor = true;
+ platform_rid = prev_platform_rid;
+ platform_layer = prev_platform_layer;
+
+ platform_velocity = prev_platform_velocity;
+ floor_normal = prev_floor_normal;
+ linear_velocity = Vector2();
+ motion = Vector2();
+ break;
}
-
- if (sliding_enabled || !on_floor) {
- motion = result.remainder.slide(result.collision_normal);
- linear_velocity = linear_velocity.slide(result.collision_normal);
+ // Prevents the body from being able to climb a slope when it moves forward against the wall.
+ else if (!is_on_floor_only()) {
+ motion = up_direction * up_direction.dot(result.remainder);
+ motion = motion.slide(result.collision_normal);
} else {
motion = result.remainder;
}
}
+ // 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) {
+ 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());
+ }
+ }
+ // 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)) {
+ Vector2 slide_motion = result.remainder.slide(result.collision_normal);
+ if (slide_motion.dot(linear_velocity) > 0.0) {
+ motion = slide_motion;
+ } else {
+ motion = Vector2();
+ }
+ if (slide_on_ceiling && on_ceiling) {
+ // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall.
+ if (vel_dir_facing_up) {
+ linear_velocity = linear_velocity.slide(result.collision_normal);
+ } else {
+ // Avoid acceleration in slope when falling.
+ linear_velocity = up_direction * up_direction.dot(linear_velocity);
+ }
+ }
+ }
+ // No sliding on first attempt to keep floor motion stable when possible.
+ else {
+ motion = result.remainder;
+ if (on_ceiling && !slide_on_ceiling && vel_dir_facing_up) {
+ linear_velocity = linear_velocity.slide(up_direction);
+ motion = motion.slide(up_direction);
+ }
+ }
+ last_travel = result.motion;
+ }
+ // 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)) {
+ can_apply_constant_speed = false;
sliding_enabled = true;
+ Transform2D gt = get_global_transform();
+ gt.elements[2] = prev_position;
+ 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;
+ }
}
- if (!found_collision || motion == Vector2()) {
+ can_apply_constant_speed = !can_apply_constant_speed && !sliding_enabled;
+ sliding_enabled = true;
+ first_slide = false;
+
+ if (!found_collision || 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_floor_velocity;
+ linear_velocity += current_platform_velocity;
}
- if (!was_on_floor || snap == Vector2()) {
+ // Reset the gravity accumulation when touching the ground.
+ if (on_floor && !vel_dir_facing_up) {
+ linear_velocity = linear_velocity.slide(up_direction);
+ }
+}
+
+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) {
return;
}
- // Apply snap.
Transform2D gt = get_global_transform();
PhysicsServer2D::MotionResult result;
- if (move_and_collide(snap, infinite_inertia, result, margin, false, true, false)) {
+ if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false)) {
bool apply = true;
- if (up_direction != Vector2()) {
- if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
- on_floor = true;
- floor_normal = result.collision_normal;
- on_floor_body = result.collider;
- floor_velocity = result.collider_velocity;
- if (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);
- } else {
- result.motion = Vector2();
- }
+ float collision_angle = Math::acos(result.collision_normal.dot(up_direction));
+ if (collision_angle <= 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) {
+ // 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);
+ } else {
+ result.motion = Vector2();
}
- } else {
- apply = false;
}
+ } else {
+ apply = false;
}
if (apply) {
@@ -1186,59 +1273,46 @@ void CharacterBody2D::move_and_slide() {
}
}
-void CharacterBody2D::_set_collision_direction(const PhysicsServer2D::MotionResult &p_result) {
- if (up_direction == Vector2()) {
- //all is a wall
- on_wall = true;
- } else {
- if (Math::acos(p_result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
- on_floor = true;
- floor_normal = p_result.collision_normal;
- on_floor_body = p_result.collider;
- floor_velocity = p_result.collider_velocity;
- } else if (Math::acos(p_result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
- on_ceiling = true;
- } else {
- on_wall = true;
- on_floor_body = p_result.collider;
- floor_velocity = p_result.collider_velocity;
- }
+bool CharacterBody2D::_on_floor_if_snapped(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) {
+ return false;
}
-}
-
-bool CharacterBody2D::separate_raycast_shapes(PhysicsServer2D::MotionResult &r_result) {
- PhysicsServer2D::SeparationResult sep_res[8]; //max 8 rays
- Transform2D gt = get_global_transform();
-
- Vector2 recover;
- int hits = PhysicsServer2D::get_singleton()->body_test_ray_separation(get_rid(), gt, infinite_inertia, recover, sep_res, 8, margin);
- int deepest = -1;
- real_t deepest_depth;
- for (int i = 0; i < hits; i++) {
- if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) {
- deepest = i;
- deepest_depth = sep_res[i].collision_depth;
+ 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) {
+ return true;
}
}
- gt.elements[2] += recover;
- set_global_transform(gt);
+ return false;
+}
- if (deepest != -1) {
- r_result.collider_id = sep_res[deepest].collider_id;
- r_result.collider_metadata = sep_res[deepest].collider_metadata;
- r_result.collider_shape = sep_res[deepest].collider_shape;
- r_result.collider_velocity = sep_res[deepest].collider_velocity;
- r_result.collision_point = sep_res[deepest].collision_point;
- r_result.collision_normal = sep_res[deepest].collision_normal;
- r_result.collision_local_shape = sep_res[deepest].collision_local_shape;
- r_result.motion = recover;
- r_result.remainder = Vector2();
+void CharacterBody2D::_set_collision_direction(const PhysicsServer2D::MotionResult &p_result) {
+ if (up_direction == Vector2()) {
+ return;
+ }
- return true;
+ if (Math::acos(p_result.collision_normal.dot(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
+ on_ceiling = true;
} else {
- return false;
+ on_wall = true;
+ platform_velocity = p_result.collider_velocity;
+ _set_platform_data(p_result);
+ }
+}
+
+void CharacterBody2D::_set_platform_data(const PhysicsServer2D::MotionResult &p_result) {
+ platform_rid = p_result.collider;
+ platform_layer = 0;
+ CollisionObject2D *collision_object = Object::cast_to<CollisionObject2D>(ObjectDB::get_instance(p_result.collider_id));
+ if (collision_object) {
+ platform_layer = collision_object->get_collision_layer();
}
}
@@ -1254,20 +1328,32 @@ bool CharacterBody2D::is_on_floor() const {
return on_floor;
}
+bool CharacterBody2D::is_on_floor_only() const {
+ return on_floor && !on_wall && !on_ceiling;
+}
+
bool CharacterBody2D::is_on_wall() const {
return on_wall;
}
+bool CharacterBody2D::is_on_wall_only() const {
+ return on_wall && !on_floor && !on_ceiling;
+}
+
bool CharacterBody2D::is_on_ceiling() const {
return on_ceiling;
}
+bool CharacterBody2D::is_on_ceiling_only() const {
+ return on_ceiling && !on_floor && !on_wall;
+}
+
Vector2 CharacterBody2D::get_floor_normal() const {
return floor_normal;
}
-Vector2 CharacterBody2D::get_floor_velocity() const {
- return floor_velocity;
+Vector2 CharacterBody2D::get_platform_velocity() const {
+ return platform_velocity;
}
int CharacterBody2D::get_slide_count() const {
@@ -1310,11 +1396,36 @@ void CharacterBody2D::set_stop_on_slope_enabled(bool p_enabled) {
stop_on_slope = p_enabled;
}
-bool CharacterBody2D::is_infinite_inertia_enabled() const {
- return infinite_inertia;
+bool CharacterBody2D::is_constant_speed_on_floor_enabled() const {
+ return constant_speed_on_floor;
+}
+
+void CharacterBody2D::set_constant_speed_on_floor_enabled(bool p_enabled) {
+ constant_speed_on_floor = p_enabled;
}
-void CharacterBody2D::set_infinite_inertia_enabled(bool p_enabled) {
- infinite_inertia = p_enabled;
+
+bool CharacterBody2D::is_move_on_floor_only_enabled() const {
+ return move_on_floor_only;
+}
+
+void CharacterBody2D::set_move_on_floor_only_enabled(bool p_enabled) {
+ move_on_floor_only = p_enabled;
+}
+
+bool CharacterBody2D::is_slide_on_ceiling_enabled() const {
+ return slide_on_ceiling;
+}
+
+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;
+}
+
+void CharacterBody2D::set_exclude_body_layers(uint32_t p_exclude_layers) {
+ exclude_body_layers = p_exclude_layers;
}
int CharacterBody2D::get_max_slides() const {
@@ -1322,7 +1433,7 @@ int CharacterBody2D::get_max_slides() const {
}
void CharacterBody2D::set_max_slides(int p_max_slides) {
- ERR_FAIL_COND(p_max_slides > 0);
+ ERR_FAIL_COND(p_max_slides < 1);
max_slides = p_max_slides;
}
@@ -1334,12 +1445,13 @@ void CharacterBody2D::set_floor_max_angle(real_t p_radians) {
floor_max_angle = p_radians;
}
-const Vector2 &CharacterBody2D::get_snap() const {
- return snap;
+real_t CharacterBody2D::get_floor_snap_length() {
+ return floor_snap_length;
}
-void CharacterBody2D::set_snap(const Vector2 &p_snap) {
- snap = p_snap;
+void CharacterBody2D::set_floor_snap_length(real_t p_floor_snap_length) {
+ ERR_FAIL_COND(p_floor_snap_length < 0);
+ floor_snap_length = p_floor_snap_length;
}
const Vector2 &CharacterBody2D::get_up_direction() const {
@@ -1355,11 +1467,11 @@ void CharacterBody2D::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
// Reset move_and_slide() data.
on_floor = false;
- on_floor_body = RID();
+ platform_rid = RID();
on_ceiling = false;
on_wall = false;
motion_results.clear();
- floor_velocity = Vector2();
+ platform_velocity = Vector2();
} break;
}
}
@@ -1374,32 +1486,46 @@ void CharacterBody2D::_bind_methods() {
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("is_infinite_inertia_enabled"), &CharacterBody2D::is_infinite_inertia_enabled);
- ClassDB::bind_method(D_METHOD("set_infinite_inertia_enabled", "enabled"), &CharacterBody2D::set_infinite_inertia_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("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("get_max_slides"), &CharacterBody2D::get_max_slides);
ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody2D::set_max_slides);
ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody2D::get_floor_max_angle);
ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody2D::set_floor_max_angle);
- ClassDB::bind_method(D_METHOD("get_snap"), &CharacterBody2D::get_snap);
- ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CharacterBody2D::set_snap);
+ 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_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("is_on_floor"), &CharacterBody2D::is_on_floor);
+ ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody2D::is_on_floor_only);
ClassDB::bind_method(D_METHOD("is_on_ceiling"), &CharacterBody2D::is_on_ceiling);
+ ClassDB::bind_method(D_METHOD("is_on_ceiling_only"), &CharacterBody2D::is_on_ceiling_only);
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_velocity"), &CharacterBody2D::get_floor_velocity);
+ 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", "slide_idx"), &CharacterBody2D::_get_slide_collision);
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, "infinite_inertia"), "set_infinite_inertia_enabled", "is_infinite_inertia_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides"), "set_max_slides", "get_max_slides");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_floor_max_angle", "get_floor_max_angle");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "snap"), "set_snap", "get_snap");
+ 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::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_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
}