Merge pull request #53149 from fabriceci/port-move-and-slide-3D-new-changes

Add latest API changes added in the 3D version of move_and_slide to the 2D version
This commit is contained in:
Camille Mohr-Daurat 2021-09-30 09:43:07 -07:00 committed by GitHub
commit 43c7448741
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 153 additions and 40 deletions

View file

@ -28,6 +28,12 @@
Returns the surface normal of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code]. Returns the surface normal of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
</description> </description>
</method> </method>
<method name="get_last_motion" qualifiers="const">
<return type="Vector2" />
<description>
Returns the last motion applied to the [CharacterBody2D] during the last call to [method move_and_slide]. The movement can be split into multiple motions when sliding occurs, and this method return the last one, which is useful to retrieve the current direction of the movement.
</description>
</method>
<method name="get_last_slide_collision"> <method name="get_last_slide_collision">
<return type="KinematicCollision2D" /> <return type="KinematicCollision2D" />
<description> <description>
@ -40,6 +46,18 @@
Returns the linear velocity of the platform at the last collision point. Only valid after calling [method move_and_slide]. Returns the linear velocity of the platform at the last collision point. Only valid after calling [method move_and_slide].
</description> </description>
</method> </method>
<method name="get_position_delta" qualifiers="const">
<return type="Vector2" />
<description>
Returns the travel (position delta) that occurred during the last call to [method move_and_slide].
</description>
</method>
<method name="get_real_velocity" qualifiers="const">
<return type="Vector2" />
<description>
Returns the current real velocity since the last call to [method move_and_slide]. For example, when you climb a slope, you will move diagonally even though the velocity is horizontal. This method returns the diagonal movement, as opposed to [member motion_velocity] which returns the requested velocity.
</description>
</method>
<method name="get_slide_collision"> <method name="get_slide_collision">
<return type="KinematicCollision2D" /> <return type="KinematicCollision2D" />
<argument index="0" name="slide_idx" type="int" /> <argument index="0" name="slide_idx" type="int" />
@ -68,6 +86,12 @@
Returns the number of times the body collided and changed direction during the last call to [method move_and_slide]. Returns the number of times the body collided and changed direction during the last call to [method move_and_slide].
</description> </description>
</method> </method>
<method name="get_wall_normal" qualifiers="const">
<return type="Vector2" />
<description>
Returns the surface normal of the wall at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_wall] returns [code]true[/code].
</description>
</method>
<method name="is_on_ceiling" qualifiers="const"> <method name="is_on_ceiling" qualifiers="const">
<return type="bool" /> <return type="bool" />
<description> <description>
@ -107,9 +131,9 @@
<method name="move_and_slide"> <method name="move_and_slide">
<return type="bool" /> <return type="bool" />
<description> <description>
Moves the body based on [member linear_velocity]. If the body collides with another, it will slide along the other body (by default only on floor) rather than stop immediately. If the other body is a [CharacterBody2D] or [RigidDynamicBody2D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes. Moves the body based on [member motion_velocity]. If the body collides with another, it will slide along the other body (by default only on floor) rather than stop immediately. If the other body is a [CharacterBody2D] or [RigidDynamicBody2D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes.
This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed.
Modifies [member linear_velocity] if a slide collision occurred. To get the latest collision call [method get_last_slide_collision], for detailed information about collisions that occurred, use [method get_slide_collision]. Modifies [member motion_velocity] if a slide collision occurred. To get the latest collision call [method get_last_slide_collision], for detailed information about collisions that occurred, use [method get_slide_collision].
When the body touches a moving platform, the platform's velocity is automatically added to the body motion. If a collision occurs due to the platform's motion, it will always be first in the slide collisions. When the body touches a moving platform, the platform's velocity is automatically added to the body motion. If a collision occurs due to the platform's motion, it will always be first in the slide collisions.
The general behaviour and available properties change according to the [member motion_mode]. The general behaviour and available properties change according to the [member motion_mode].
Returns [code]true[/code] if the body collided, otherwise, returns [code]false[/code]. Returns [code]true[/code] if the body collided, otherwise, returns [code]false[/code].
@ -138,20 +162,24 @@
As long as the snapping vector is in contact with the ground and the body moves against `up_direction`, the body will remain attached to the surface. Snapping is not applied if the body moves along `up_direction`, so it will be able to detach from the ground when jumping. As long as the snapping vector is in contact with the ground and the body moves against `up_direction`, the body will remain attached to the surface. Snapping is not applied if the body moves along `up_direction`, so it will be able to detach from the ground when jumping.
</member> </member>
<member name="floor_stop_on_slope" type="bool" setter="set_floor_stop_on_slope_enabled" getter="is_floor_stop_on_slope_enabled" default="true"> <member name="floor_stop_on_slope" type="bool" setter="set_floor_stop_on_slope_enabled" getter="is_floor_stop_on_slope_enabled" default="true">
If [code]true[/code], the body will not slide on floor's slopes when you include gravity in [code]linear_velocity[/code] when calling [method move_and_slide] and the body is standing still. If [code]true[/code], the body will not slide on slopes when calling [method move_and_slide] when the body is standing still.
If [code]false[/code], the body will slide on floor's slopes when [member motion_velocity] applies a downward force.
</member> </member>
<member name="free_mode_min_slide_angle" type="float" setter="set_free_mode_min_slide_angle" getter="get_free_mode_min_slide_angle" default="0.261799"> <member name="free_mode_min_slide_angle" type="float" setter="set_free_mode_min_slide_angle" getter="get_free_mode_min_slide_angle" default="0.261799">
Minimum angle (in radians) where the body is allowed to slide when it encounters a slope. The default value equals 15 degrees. Minimum angle (in radians) where the body is allowed to slide when it encounters a slope. The default value equals 15 degrees.
</member> </member>
<member name="linear_velocity" type="Vector2" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector2(0, 0)">
Current velocity vector in pixels per second, used and modified during calls to [method move_and_slide].
</member>
<member name="max_slides" type="int" setter="set_max_slides" getter="get_max_slides" default="4"> <member name="max_slides" type="int" setter="set_max_slides" getter="get_max_slides" default="4">
Maximum number of times the body can change direction before it stops when calling [method move_and_slide]. Maximum number of times the body can change direction before it stops when calling [method move_and_slide].
</member> </member>
<member name="motion_mode" type="int" setter="set_motion_mode" getter="get_motion_mode" enum="CharacterBody2D.MotionMode" default="0"> <member name="motion_mode" type="int" setter="set_motion_mode" getter="get_motion_mode" enum="CharacterBody2D.MotionMode" default="0">
Sets the motion mode which defines the behaviour of [method move_and_slide]. See [enum MotionMode] constants for available modes. Sets the motion mode which defines the behaviour of [method move_and_slide]. See [enum MotionMode] constants for available modes.
</member> </member>
<member name="motion_velocity" type="Vector2" setter="set_motion_velocity" getter="get_motion_velocity" default="Vector2(0, 0)">
Current velocity vector in pixels per second, used and modified during calls to [method move_and_slide].
</member>
<member name="moving_platform_apply_velocity_on_leave" type="int" setter="set_moving_platform_apply_velocity_on_leave" getter="get_moving_platform_apply_velocity_on_leave" enum="CharacterBody2D.MovingPlatformApplyVelocityOnLeave" default="0">
Sets the behaviour to apply when you leave a moving platform. By default, to be physically accurate, when you leave the last platform velocity is applied. See [enum MovingPlatformApplyVelocityOnLeave] constants for available behaviour.
</member>
<member name="moving_platform_floor_layers" type="int" setter="set_moving_platform_floor_layers" getter="get_moving_platform_floor_layers" default="4294967295"> <member name="moving_platform_floor_layers" type="int" setter="set_moving_platform_floor_layers" getter="get_moving_platform_floor_layers" default="4294967295">
Collision layers that will be included for detecting floor bodies that will act as moving platforms to be followed by the [CharacterBody2D]. By default, all floor bodies are detected and propagate their velocity. Collision layers that will be included for detecting floor bodies that will act as moving platforms to be followed by the [CharacterBody2D]. By default, all floor bodies are detected and propagate their velocity.
</member> </member>
@ -172,5 +200,14 @@
<constant name="MOTION_MODE_FREE" value="1" enum="MotionMode"> <constant name="MOTION_MODE_FREE" value="1" enum="MotionMode">
Apply when there is no notion of floor or ceiling. All collisions will be reported as [code]on_wall[/code]. In this mode, when you slide, the speed will always be constant. This mode is suitable for top-down games. Apply when there is no notion of floor or ceiling. All collisions will be reported as [code]on_wall[/code]. In this mode, when you slide, the speed will always be constant. This mode is suitable for top-down games.
</constant> </constant>
<constant name="PLATFORM_VEL_ON_LEAVE_ALWAYS" value="0" enum="MovingPlatformApplyVelocityOnLeave">
Add the last platform velocity to the [member motion_velocity] when you leave a moving platform.
</constant>
<constant name="PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY" value="1" enum="MovingPlatformApplyVelocityOnLeave">
Add the last platform velocity to the [member motion_velocity] when you leave a moving platform, but any downward motion is ignored. It's useful to keep full jump height even when the platform is moving down.
</constant>
<constant name="PLATFORM_VEL_ON_LEAVE_NEVER" value="2" enum="MovingPlatformApplyVelocityOnLeave">
Do nothing when leaving a platform.
</constant>
</constants> </constants>
</class> </class>

View file

@ -1052,6 +1052,8 @@ bool CharacterBody2D::move_and_slide() {
double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
Vector2 current_platform_velocity = platform_velocity; Vector2 current_platform_velocity = platform_velocity;
Transform2D gt = get_global_transform();
previous_position = gt.elements[2];
if ((on_floor || on_wall) && platform_rid.is_valid()) { if ((on_floor || on_wall) && platform_rid.is_valid()) {
bool excluded = false; bool excluded = false;
@ -1064,7 +1066,6 @@ bool CharacterBody2D::move_and_slide() {
//this approach makes sure there is less delay between the actual body velocity and the one we saved //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); PhysicsDirectBodyState2D *bs = PhysicsServer2D::get_singleton()->body_get_direct_state(platform_rid);
if (bs) { if (bs) {
Transform2D gt = get_global_transform();
Vector2 local_position = gt.elements[2] - bs->get_transform().elements[2]; Vector2 local_position = gt.elements[2] - bs->get_transform().elements[2];
current_platform_velocity = bs->get_velocity_at_local_position(local_position); current_platform_velocity = bs->get_velocity_at_local_position(local_position);
} }
@ -1074,6 +1075,7 @@ bool CharacterBody2D::move_and_slide() {
} }
motion_results.clear(); motion_results.clear();
last_motion = Vector2();
bool was_on_floor = on_floor; bool was_on_floor = on_floor;
on_floor = false; on_floor = false;
@ -1096,16 +1098,24 @@ bool CharacterBody2D::move_and_slide() {
_move_and_slide_free(delta); _move_and_slide_free(delta);
} }
if (!on_floor && !on_wall) { // Compute real velocity.
real_velocity = get_position_delta() / delta;
if (moving_platform_apply_velocity_on_leave != PLATFORM_VEL_ON_LEAVE_NEVER) {
// Add last platform velocity when just left a moving platform. // Add last platform velocity when just left a moving platform.
linear_velocity += current_platform_velocity; if (!on_floor && !on_wall) {
if (moving_platform_apply_velocity_on_leave == PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY && current_platform_velocity.dot(up_direction) < 0) {
current_platform_velocity = current_platform_velocity.slide(up_direction);
}
motion_velocity += current_platform_velocity;
}
} }
return motion_results.size() > 0; return motion_results.size() > 0;
} }
void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor, const Vector2 &p_prev_platform_velocity) { void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor, const Vector2 &p_prev_platform_velocity) {
Vector2 motion = linear_velocity * p_delta; Vector2 motion = motion_velocity * p_delta;
Vector2 motion_slide_up = motion.slide(up_direction); Vector2 motion_slide_up = motion.slide(up_direction);
Vector2 prev_floor_normal = floor_normal; Vector2 prev_floor_normal = floor_normal;
@ -1122,7 +1132,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
// Constant speed can be applied only the first time sliding is enabled. // Constant speed can be applied only the first time sliding is enabled.
bool can_apply_constant_speed = sliding_enabled; bool can_apply_constant_speed = sliding_enabled;
bool first_slide = true; bool first_slide = true;
bool vel_dir_facing_up = linear_velocity.dot(up_direction) > 0; bool vel_dir_facing_up = motion_velocity.dot(up_direction) > 0;
Vector2 last_travel; Vector2 last_travel;
for (int iteration = 0; iteration < max_slides; ++iteration) { for (int iteration = 0; iteration < max_slides; ++iteration) {
@ -1131,18 +1141,20 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
Vector2 prev_position = get_global_transform().elements[2]; Vector2 prev_position = get_global_transform().elements[2];
bool collided = move_and_collide(motion, result, margin, false, !sliding_enabled); bool collided = move_and_collide(motion, result, margin, false, !sliding_enabled);
last_motion = result.travel;
if (collided) { if (collided) {
motion_results.push_back(result); motion_results.push_back(result);
_set_collision_direction(result); _set_collision_direction(result);
if (on_floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) { if (on_floor && floor_stop_on_slope && (motion_velocity.normalized() + up_direction).length() < 0.01) {
Transform2D gt = get_global_transform(); Transform2D gt = get_global_transform();
if (result.travel.length() <= margin + CMP_EPSILON) { if (result.travel.length() <= margin + CMP_EPSILON) {
gt.elements[2] -= result.travel; gt.elements[2] -= result.travel;
} }
set_global_transform(gt); set_global_transform(gt);
linear_velocity = Vector2(); motion_velocity = Vector2();
last_motion = Vector2();
motion = Vector2(); motion = Vector2();
break; break;
} }
@ -1168,7 +1180,8 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
platform_layer = prev_platform_layer; platform_layer = prev_platform_layer;
platform_velocity = p_prev_platform_velocity; platform_velocity = p_prev_platform_velocity;
floor_normal = prev_floor_normal; floor_normal = prev_floor_normal;
linear_velocity = Vector2(); motion_velocity = Vector2();
last_motion = Vector2();
motion = Vector2(); motion = Vector2();
break; break;
} }
@ -1189,7 +1202,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
// Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling. // 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)) {
Vector2 slide_motion = result.remainder.slide(result.collision_normal); Vector2 slide_motion = result.remainder.slide(result.collision_normal);
if (slide_motion.dot(linear_velocity) > 0.0) { if (slide_motion.dot(motion_velocity) > 0.0) {
motion = slide_motion; motion = slide_motion;
} else { } else {
motion = Vector2(); motion = Vector2();
@ -1197,10 +1210,10 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
if (slide_on_ceiling && on_ceiling) { 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. // 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) { if (vel_dir_facing_up) {
linear_velocity = linear_velocity.slide(result.collision_normal); motion_velocity = motion_velocity.slide(result.collision_normal);
} else { } else {
// Avoid acceleration in slope when falling. // Avoid acceleration in slope when falling.
linear_velocity = up_direction * up_direction.dot(linear_velocity); motion_velocity = up_direction * up_direction.dot(motion_velocity);
} }
} }
} }
@ -1208,7 +1221,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
else { else {
motion = result.remainder; motion = result.remainder;
if (on_ceiling && !slide_on_ceiling && vel_dir_facing_up) { if (on_ceiling && !slide_on_ceiling && vel_dir_facing_up) {
linear_velocity = linear_velocity.slide(up_direction); motion_velocity = motion_velocity.slide(up_direction);
motion = motion.slide(up_direction); motion = motion.slide(up_direction);
} }
} }
@ -1242,12 +1255,12 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
// Reset the gravity accumulation when touching the ground. // Reset the gravity accumulation when touching the ground.
if (on_floor && !vel_dir_facing_up) { if (on_floor && !vel_dir_facing_up) {
linear_velocity = linear_velocity.slide(up_direction); motion_velocity = motion_velocity.slide(up_direction);
} }
} }
void CharacterBody2D::_move_and_slide_free(double p_delta) { void CharacterBody2D::_move_and_slide_free(double p_delta) {
Vector2 motion = linear_velocity * p_delta; Vector2 motion = motion_velocity * p_delta;
platform_rid = RID(); platform_rid = RID();
floor_normal = Vector2(); floor_normal = Vector2();
@ -1258,12 +1271,18 @@ void CharacterBody2D::_move_and_slide_free(double p_delta) {
PhysicsServer2D::MotionResult result; PhysicsServer2D::MotionResult result;
bool collided = move_and_collide(motion, result, margin, false, false); bool collided = move_and_collide(motion, result, margin, false, false);
last_motion = result.travel;
if (collided) { if (collided) {
motion_results.push_back(result); motion_results.push_back(result);
_set_collision_direction(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) { if (result.remainder.is_equal_approx(Vector2())) {
motion = Vector2();
break;
}
if (free_mode_min_slide_angle != 0 && result.get_angle(-motion_velocity.normalized()) < free_mode_min_slide_angle + FLOOR_ANGLE_THRESHOLD) {
motion = Vector2(); motion = Vector2();
} else if (first_slide) { } else if (first_slide) {
Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized(); Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized();
@ -1272,16 +1291,16 @@ void CharacterBody2D::_move_and_slide_free(double p_delta) {
motion = result.remainder.slide(result.collision_normal); motion = result.remainder.slide(result.collision_normal);
} }
if (motion.dot(linear_velocity) <= 0.0) { if (motion.dot(motion_velocity) <= 0.0) {
motion = Vector2(); motion = Vector2();
} }
} }
first_slide = false;
if (!collided || motion.is_equal_approx(Vector2())) { if (!collided || motion.is_equal_approx(Vector2())) {
break; break;
} }
first_slide = false;
} }
} }
@ -1349,6 +1368,7 @@ void CharacterBody2D::_set_collision_direction(const PhysicsServer2D::MotionResu
on_ceiling = true; on_ceiling = true;
} else { } else {
on_wall = true; on_wall = true;
wall_normal = p_result.collision_normal;
// Don't apply wall velocity when the collider is a CharacterBody2D. // Don't apply wall velocity when the collider is a CharacterBody2D.
if (Object::cast_to<CharacterBody2D>(ObjectDB::get_instance(p_result.collider_id)) == nullptr) { if (Object::cast_to<CharacterBody2D>(ObjectDB::get_instance(p_result.collider_id)) == nullptr) {
_set_platform_data(p_result); _set_platform_data(p_result);
@ -1362,12 +1382,12 @@ void CharacterBody2D::_set_platform_data(const PhysicsServer2D::MotionResult &p_
platform_layer = PhysicsServer2D::get_singleton()->body_get_collision_layer(platform_rid); platform_layer = PhysicsServer2D::get_singleton()->body_get_collision_layer(platform_rid);
} }
const Vector2 &CharacterBody2D::get_linear_velocity() const { const Vector2 &CharacterBody2D::get_motion_velocity() const {
return linear_velocity; return motion_velocity;
} }
void CharacterBody2D::set_linear_velocity(const Vector2 &p_velocity) { void CharacterBody2D::set_motion_velocity(const Vector2 &p_velocity) {
linear_velocity = p_velocity; motion_velocity = p_velocity;
} }
bool CharacterBody2D::is_on_floor() const { bool CharacterBody2D::is_on_floor() const {
@ -1394,16 +1414,32 @@ bool CharacterBody2D::is_on_ceiling_only() const {
return on_ceiling && !on_floor && !on_wall; return on_ceiling && !on_floor && !on_wall;
} }
Vector2 CharacterBody2D::get_floor_normal() const { const Vector2 &CharacterBody2D::get_floor_normal() const {
return floor_normal; return floor_normal;
} }
const Vector2 &CharacterBody2D::get_wall_normal() const {
return wall_normal;
}
const Vector2 &CharacterBody2D::get_last_motion() const {
return last_motion;
}
Vector2 CharacterBody2D::get_position_delta() const {
return get_global_transform().elements[2] - previous_position;
}
const Vector2 &CharacterBody2D::get_real_velocity() const {
return real_velocity;
}
real_t CharacterBody2D::get_floor_angle(const Vector2 &p_up_direction) const { real_t CharacterBody2D::get_floor_angle(const Vector2 &p_up_direction) const {
ERR_FAIL_COND_V(p_up_direction == Vector2(), 0); ERR_FAIL_COND_V(p_up_direction == Vector2(), 0);
return Math::acos(floor_normal.dot(p_up_direction)); return Math::acos(floor_normal.dot(p_up_direction));
} }
Vector2 CharacterBody2D::get_platform_velocity() const { const Vector2 &CharacterBody2D::get_platform_velocity() const {
return platform_velocity; return platform_velocity;
} }
@ -1503,6 +1539,14 @@ CharacterBody2D::MotionMode CharacterBody2D::get_motion_mode() const {
return motion_mode; return motion_mode;
} }
void CharacterBody2D::set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_apply_velocity) {
moving_platform_apply_velocity_on_leave = p_on_leave_apply_velocity;
}
CharacterBody2D::MovingPlatformApplyVelocityOnLeave CharacterBody2D::get_moving_platform_apply_velocity_on_leave() const {
return moving_platform_apply_velocity_on_leave;
}
int CharacterBody2D::get_max_slides() const { int CharacterBody2D::get_max_slides() const {
return max_slides; return max_slides;
} }
@ -1563,8 +1607,8 @@ void CharacterBody2D::_notification(int p_what) {
void CharacterBody2D::_bind_methods() { void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody2D::move_and_slide); ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody2D::move_and_slide);
ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &CharacterBody2D::set_linear_velocity); ClassDB::bind_method(D_METHOD("set_motion_velocity", "motion_velocity"), &CharacterBody2D::set_motion_velocity);
ClassDB::bind_method(D_METHOD("get_linear_velocity"), &CharacterBody2D::get_linear_velocity); ClassDB::bind_method(D_METHOD("get_motion_velocity"), &CharacterBody2D::get_motion_velocity);
ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody2D::set_safe_margin); 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("get_safe_margin"), &CharacterBody2D::get_safe_margin);
@ -1594,6 +1638,8 @@ void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody2D::set_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("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("get_motion_mode"), &CharacterBody2D::get_motion_mode);
ClassDB::bind_method(D_METHOD("set_moving_platform_apply_velocity_on_leave", "on_leave_apply_velocity"), &CharacterBody2D::set_moving_platform_apply_velocity_on_leave);
ClassDB::bind_method(D_METHOD("get_moving_platform_apply_velocity_on_leave"), &CharacterBody2D::get_moving_platform_apply_velocity_on_leave);
ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody2D::is_on_floor); 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_floor_only"), &CharacterBody2D::is_on_floor_only);
@ -1602,6 +1648,10 @@ void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody2D::is_on_wall); 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("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_normal"), &CharacterBody2D::get_floor_normal);
ClassDB::bind_method(D_METHOD("get_wall_normal"), &CharacterBody2D::get_wall_normal);
ClassDB::bind_method(D_METHOD("get_last_motion"), &CharacterBody2D::get_last_motion);
ClassDB::bind_method(D_METHOD("get_position_delta"), &CharacterBody2D::get_position_delta);
ClassDB::bind_method(D_METHOD("get_real_velocity"), &CharacterBody2D::get_real_velocity);
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_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_platform_velocity"), &CharacterBody2D::get_platform_velocity);
ClassDB::bind_method(D_METHOD("get_slide_collision_count"), &CharacterBody2D::get_slide_collision_count); ClassDB::bind_method(D_METHOD("get_slide_collision_count"), &CharacterBody2D::get_slide_collision_count);
@ -1609,10 +1659,11 @@ void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody2D::_get_last_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::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::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_motion_velocity", "get_motion_velocity");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_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_NONE, "", PROPERTY_USAGE_NOEDITOR), "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_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_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_GROUP("Floor", "floor_");
@ -1622,12 +1673,17 @@ void CharacterBody2D::_bind_methods() {
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_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,32,0.1,or_greater"), "set_floor_snap_length", "get_floor_snap_length"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater"), "set_floor_snap_length", "get_floor_snap_length");
ADD_GROUP("Moving platform", "moving_platform"); ADD_GROUP("Moving platform", "moving_platform");
ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_apply_velocity_on_leave", PROPERTY_HINT_ENUM, "Always,Upward Only,Never", PROPERTY_USAGE_DEFAULT), "set_moving_platform_apply_velocity_on_leave", "get_moving_platform_apply_velocity_on_leave");
ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_floor_layers", "get_moving_platform_floor_layers"); ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_floor_layers", "get_moving_platform_floor_layers");
ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_wall_layers", "get_moving_platform_wall_layers"); ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_wall_layers", "get_moving_platform_wall_layers");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); 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_GROUNDED);
BIND_ENUM_CONSTANT(MOTION_MODE_FREE); BIND_ENUM_CONSTANT(MOTION_MODE_FREE);
BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_ALWAYS);
BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY);
BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_NEVER);
} }
void CharacterBody2D::_validate_property(PropertyInfo &property) const { void CharacterBody2D::_validate_property(PropertyInfo &property) const {

View file

@ -310,10 +310,15 @@ public:
MOTION_MODE_GROUNDED, MOTION_MODE_GROUNDED,
MOTION_MODE_FREE, MOTION_MODE_FREE,
}; };
enum MovingPlatformApplyVelocityOnLeave {
PLATFORM_VEL_ON_LEAVE_ALWAYS,
PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY,
PLATFORM_VEL_ON_LEAVE_NEVER,
};
bool move_and_slide(); bool move_and_slide();
const Vector2 &get_linear_velocity() const; const Vector2 &get_motion_velocity() const;
void set_linear_velocity(const Vector2 &p_velocity); void set_motion_velocity(const Vector2 &p_velocity);
bool is_on_floor() const; bool is_on_floor() const;
bool is_on_floor_only() const; bool is_on_floor_only() const;
@ -321,9 +326,14 @@ public:
bool is_on_wall_only() const; bool is_on_wall_only() const;
bool is_on_ceiling() const; bool is_on_ceiling() const;
bool is_on_ceiling_only() const; bool is_on_ceiling_only() const;
Vector2 get_floor_normal() const; const Vector2 &get_last_motion() const;
Vector2 get_position_delta() const;
const Vector2 &get_floor_normal() const;
const Vector2 &get_wall_normal() const;
const Vector2 &get_real_velocity() const;
real_t get_floor_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const; real_t get_floor_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const;
Vector2 get_platform_velocity() const; const Vector2 &get_platform_velocity() const;
int get_slide_collision_count() const; int get_slide_collision_count() const;
PhysicsServer2D::MotionResult get_slide_collision(int p_bounce) const; PhysicsServer2D::MotionResult get_slide_collision(int p_bounce) const;
@ -334,23 +344,29 @@ public:
private: private:
real_t margin = 0.08; real_t margin = 0.08;
MotionMode motion_mode = MOTION_MODE_GROUNDED; MotionMode motion_mode = MOTION_MODE_GROUNDED;
MovingPlatformApplyVelocityOnLeave moving_platform_apply_velocity_on_leave = PLATFORM_VEL_ON_LEAVE_ALWAYS;
bool floor_constant_speed = false; bool floor_constant_speed = false;
bool floor_stop_on_slope = true; bool floor_stop_on_slope = true;
bool floor_block_on_wall = true; bool floor_block_on_wall = true;
bool slide_on_ceiling = true; bool slide_on_ceiling = true;
int max_slides = 4; int max_slides = 4;
int platform_layer; int platform_layer = 0;
real_t floor_max_angle = Math::deg2rad((real_t)45.0); real_t floor_max_angle = Math::deg2rad((real_t)45.0);
real_t floor_snap_length = 1; real_t floor_snap_length = 1;
real_t free_mode_min_slide_angle = Math::deg2rad((real_t)15.0); real_t free_mode_min_slide_angle = Math::deg2rad((real_t)15.0);
Vector2 up_direction = Vector2(0.0, -1.0); Vector2 up_direction = Vector2(0.0, -1.0);
uint32_t moving_platform_floor_layers = UINT32_MAX; uint32_t moving_platform_floor_layers = UINT32_MAX;
uint32_t moving_platform_wall_layers = 0; uint32_t moving_platform_wall_layers = 0;
Vector2 linear_velocity; Vector2 motion_velocity;
Vector2 floor_normal; Vector2 floor_normal;
Vector2 platform_velocity; Vector2 platform_velocity;
Vector2 wall_normal;
Vector2 last_motion;
Vector2 previous_position;
Vector2 real_velocity;
RID platform_rid; RID platform_rid;
bool on_floor = false; bool on_floor = false;
bool on_ceiling = false; bool on_ceiling = false;
@ -395,6 +411,9 @@ private:
void set_motion_mode(MotionMode p_mode); void set_motion_mode(MotionMode p_mode);
MotionMode get_motion_mode() const; MotionMode get_motion_mode() const;
void set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_velocity);
MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() const;
void _move_and_slide_free(double p_delta); void _move_and_slide_free(double p_delta);
void _move_and_slide_grounded(double p_delta, bool p_was_on_floor, const Vector2 &p_prev_platform_velocity); void _move_and_slide_grounded(double p_delta, bool p_was_on_floor, const Vector2 &p_prev_platform_velocity);
@ -414,6 +433,7 @@ protected:
}; };
VARIANT_ENUM_CAST(CharacterBody2D::MotionMode); VARIANT_ENUM_CAST(CharacterBody2D::MotionMode);
VARIANT_ENUM_CAST(CharacterBody2D::MovingPlatformApplyVelocityOnLeave);
class KinematicCollision2D : public RefCounted { class KinematicCollision2D : public RefCounted {
GDCLASS(KinematicCollision2D, RefCounted); GDCLASS(KinematicCollision2D, RefCounted);