Merge pull request #53197 from nekomatata/fix-motion-direction-in-slope
Fix motion direction in slope for CharacterBody3D
This commit is contained in:
commit
767bde8c28
@ -32,7 +32,7 @@
|
|||||||
<method name="get_last_motion" qualifiers="const">
|
<method name="get_last_motion" qualifiers="const">
|
||||||
<return type="Vector3" />
|
<return type="Vector3" />
|
||||||
<description>
|
<description>
|
||||||
Returns the last motion applied to the [CharacterBody3D] during the last call to [method move_and_slide]. The movement can be split if needed into multiple motion, this method return the last one, it's useful to retrieve the current direction of the movement.
|
Returns the last motion applied to the [CharacterBody3D] 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>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_last_slide_collision">
|
<method name="get_last_slide_collision">
|
||||||
@ -56,7 +56,7 @@
|
|||||||
<method name="get_real_velocity" qualifiers="const">
|
<method name="get_real_velocity" qualifiers="const">
|
||||||
<return type="Vector3" />
|
<return type="Vector3" />
|
||||||
<description>
|
<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 linear_velocity] which returns the requested velocity.
|
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>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_slide_collision">
|
<method name="get_slide_collision">
|
||||||
@ -117,9 +117,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 rather than stop immediately. If the other body is a [CharacterBody3D] or [RigidDynamicBody3D], 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 rather than stop immediately. If the other body is a [CharacterBody3D] or [RigidDynamicBody3D], 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 more 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 more 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.
|
||||||
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].
|
||||||
</description>
|
</description>
|
||||||
@ -147,10 +147,8 @@
|
|||||||
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 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.
|
||||||
</member>
|
If [code]false[/code], the body will slide on floor's slopes when [member motion_velocity] applies a downward force.
|
||||||
<member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector3(0, 0, 0)">
|
|
||||||
Current velocity vector (typically meters per second), used and modified during calls to [method move_and_slide].
|
|
||||||
</member>
|
</member>
|
||||||
<member name="max_slides" type="int" setter="set_max_slides" getter="get_max_slides" default="6">
|
<member name="max_slides" type="int" setter="set_max_slides" getter="get_max_slides" default="6">
|
||||||
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].
|
||||||
@ -158,6 +156,9 @@
|
|||||||
<member name="motion_mode" type="int" setter="set_motion_mode" getter="get_motion_mode" enum="CharacterBody3D.MotionMode" default="0">
|
<member name="motion_mode" type="int" setter="set_motion_mode" getter="get_motion_mode" enum="CharacterBody3D.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="Vector3" setter="set_motion_velocity" getter="get_motion_velocity" default="Vector3(0, 0, 0)">
|
||||||
|
Current velocity vector (typically meters 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="CharacterBody3D.MovingPlatformApplyVelocityOnLeave" default="0">
|
<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="CharacterBody3D.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.
|
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>
|
||||||
@ -185,10 +186,10 @@
|
|||||||
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 games without ground like space 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 games without ground like space games.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PLATFORM_VEL_ON_LEAVE_ALWAYS" value="0" enum="MovingPlatformApplyVelocityOnLeave">
|
<constant name="PLATFORM_VEL_ON_LEAVE_ALWAYS" value="0" enum="MovingPlatformApplyVelocityOnLeave">
|
||||||
Add the last platform velocity to the [member linear_velocity] when you leave a moving platform.
|
Add the last platform velocity to the [member motion_velocity] when you leave a moving platform.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY" value="1" enum="MovingPlatformApplyVelocityOnLeave">
|
<constant name="PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY" value="1" enum="MovingPlatformApplyVelocityOnLeave">
|
||||||
Add the last platform velocity to the [member linear_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.
|
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>
|
||||||
<constant name="PLATFORM_VEL_ON_LEAVE_NEVER" value="2" enum="MovingPlatformApplyVelocityOnLeave">
|
<constant name="PLATFORM_VEL_ON_LEAVE_NEVER" value="2" enum="MovingPlatformApplyVelocityOnLeave">
|
||||||
Do nothing when leaving a platform.
|
Do nothing when leaving a platform.
|
||||||
|
@ -1089,13 +1089,16 @@ void RigidDynamicBody3D::_reload_physics_characteristics() {
|
|||||||
bool CharacterBody3D::move_and_slide() {
|
bool CharacterBody3D::move_and_slide() {
|
||||||
// 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
|
||||||
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();
|
||||||
previous_position = get_global_transform().origin;
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
if (locked_axis & (1 << i)) {
|
if (locked_axis & (1 << i)) {
|
||||||
linear_velocity[i] = 0.0;
|
motion_velocity[i] = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform3D gt = get_global_transform();
|
||||||
|
previous_position = gt.origin;
|
||||||
|
|
||||||
Vector3 current_platform_velocity = platform_velocity;
|
Vector3 current_platform_velocity = platform_velocity;
|
||||||
|
|
||||||
if ((collision_state.floor || collision_state.wall) && platform_rid.is_valid()) {
|
if ((collision_state.floor || collision_state.wall) && platform_rid.is_valid()) {
|
||||||
@ -1109,7 +1112,6 @@ bool CharacterBody3D::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
|
||||||
PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(platform_rid);
|
PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(platform_rid);
|
||||||
if (bs) {
|
if (bs) {
|
||||||
Transform3D gt = get_global_transform();
|
|
||||||
Vector3 local_position = gt.origin - bs->get_transform().origin;
|
Vector3 local_position = gt.origin - bs->get_transform().origin;
|
||||||
current_platform_velocity = bs->get_velocity_at_local_position(local_position);
|
current_platform_velocity = bs->get_velocity_at_local_position(local_position);
|
||||||
}
|
}
|
||||||
@ -1123,6 +1125,8 @@ bool CharacterBody3D::move_and_slide() {
|
|||||||
bool was_on_floor = collision_state.floor;
|
bool was_on_floor = collision_state.floor;
|
||||||
collision_state.state = 0;
|
collision_state.state = 0;
|
||||||
|
|
||||||
|
last_motion = Vector3();
|
||||||
|
|
||||||
if (!current_platform_velocity.is_equal_approx(Vector3())) {
|
if (!current_platform_velocity.is_equal_approx(Vector3())) {
|
||||||
PhysicsServer3D::MotionResult floor_result;
|
PhysicsServer3D::MotionResult floor_result;
|
||||||
Set<RID> exclude;
|
Set<RID> exclude;
|
||||||
@ -1150,20 +1154,15 @@ bool CharacterBody3D::move_and_slide() {
|
|||||||
if (moving_platform_apply_velocity_on_leave == PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY && current_platform_velocity.dot(up_direction) < 0) {
|
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);
|
current_platform_velocity = current_platform_velocity.slide(up_direction);
|
||||||
}
|
}
|
||||||
linear_velocity += current_platform_velocity;
|
motion_velocity += current_platform_velocity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the gravity accumulation when touching the ground.
|
|
||||||
if (collision_state.floor && linear_velocity.dot(up_direction) <= 0) {
|
|
||||||
linear_velocity = linear_velocity.slide(up_direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
return motion_results.size() > 0;
|
return motion_results.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) {
|
void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) {
|
||||||
Vector3 motion = linear_velocity * p_delta;
|
Vector3 motion = motion_velocity * p_delta;
|
||||||
Vector3 motion_slide_up = motion.slide(up_direction);
|
Vector3 motion_slide_up = motion.slide(up_direction);
|
||||||
Vector3 prev_floor_normal = floor_normal;
|
Vector3 prev_floor_normal = floor_normal;
|
||||||
|
|
||||||
@ -1178,12 +1177,13 @@ void CharacterBody3D::_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;
|
||||||
Vector3 total_travel;
|
Vector3 total_travel;
|
||||||
|
|
||||||
for (int iteration = 0; iteration < max_slides; ++iteration) {
|
for (int iteration = 0; iteration < max_slides; ++iteration) {
|
||||||
PhysicsServer3D::MotionResult result;
|
PhysicsServer3D::MotionResult result;
|
||||||
bool collided = move_and_collide(motion, result, margin, false, 4, !sliding_enabled);
|
bool collided = move_and_collide(motion, result, margin, false, 4, !sliding_enabled);
|
||||||
|
last_motion = result.travel;
|
||||||
|
|
||||||
if (collided) {
|
if (collided) {
|
||||||
motion_results.push_back(result);
|
motion_results.push_back(result);
|
||||||
@ -1193,20 +1193,20 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
|
|||||||
CollisionState result_state;
|
CollisionState result_state;
|
||||||
_set_collision_direction(result, result_state);
|
_set_collision_direction(result, result_state);
|
||||||
|
|
||||||
if (collision_state.floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) {
|
if (collision_state.floor && floor_stop_on_slope && (motion_velocity.normalized() + up_direction).length() < 0.01) {
|
||||||
Transform3D gt = get_global_transform();
|
Transform3D gt = get_global_transform();
|
||||||
if (result.travel.length() <= margin + CMP_EPSILON) {
|
if (result.travel.length() <= margin + CMP_EPSILON) {
|
||||||
gt.origin -= result.travel;
|
gt.origin -= result.travel;
|
||||||
}
|
}
|
||||||
set_global_transform(gt);
|
set_global_transform(gt);
|
||||||
linear_velocity = Vector3();
|
motion_velocity = Vector3();
|
||||||
motion = Vector3();
|
motion = Vector3();
|
||||||
|
last_motion = Vector3();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.remainder.is_equal_approx(Vector3())) {
|
if (result.remainder.is_equal_approx(Vector3())) {
|
||||||
motion = Vector3();
|
motion = Vector3();
|
||||||
last_motion = result.travel;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1255,7 +1255,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
|
|||||||
Vector3 forward = wall_normal.slide(up_direction).normalized();
|
Vector3 forward = wall_normal.slide(up_direction).normalized();
|
||||||
motion = motion.slide(forward);
|
motion = motion.slide(forward);
|
||||||
// Avoid accelerating when you jump on the wall and smooth falling.
|
// Avoid accelerating when you jump on the wall and smooth falling.
|
||||||
linear_velocity = linear_velocity.slide(forward);
|
motion_velocity = motion_velocity.slide(forward);
|
||||||
|
|
||||||
// Allow only lateral motion along previous floor when already on floor.
|
// Allow only lateral motion along previous floor when already on floor.
|
||||||
// Fixes slowing down when moving in diagonal against an inclined wall.
|
// Fixes slowing down when moving in diagonal against an inclined wall.
|
||||||
@ -1284,7 +1284,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
|
|||||||
|
|
||||||
if (stop_all_motion) {
|
if (stop_all_motion) {
|
||||||
motion = Vector3();
|
motion = Vector3();
|
||||||
linear_velocity = Vector3();
|
motion_velocity = Vector3();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1295,7 +1295,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
|
|||||||
real_t motion_angle = Math::abs(Math::acos(-horizontal_normal.dot(motion_slide_up.normalized())));
|
real_t motion_angle = Math::abs(Math::acos(-horizontal_normal.dot(motion_slide_up.normalized())));
|
||||||
if (motion_angle < wall_min_slide_angle) {
|
if (motion_angle < wall_min_slide_angle) {
|
||||||
motion = up_direction * motion.dot(up_direction);
|
motion = up_direction * motion.dot(up_direction);
|
||||||
linear_velocity = up_direction * linear_velocity.dot(up_direction);
|
motion_velocity = up_direction * motion_velocity.dot(up_direction);
|
||||||
|
|
||||||
apply_default_sliding = false;
|
apply_default_sliding = false;
|
||||||
}
|
}
|
||||||
@ -1306,19 +1306,33 @@ void CharacterBody3D::_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.
|
||||||
if ((sliding_enabled || !collision_state.floor) && (!collision_state.ceiling || slide_on_ceiling || !vel_dir_facing_up)) {
|
if ((sliding_enabled || !collision_state.floor) && (!collision_state.ceiling || slide_on_ceiling || !vel_dir_facing_up)) {
|
||||||
const PhysicsServer3D::MotionCollision &collision = result.collisions[0];
|
const PhysicsServer3D::MotionCollision &collision = result.collisions[0];
|
||||||
|
|
||||||
Vector3 slide_motion = result.remainder.slide(collision.normal);
|
Vector3 slide_motion = result.remainder.slide(collision.normal);
|
||||||
if (slide_motion.dot(linear_velocity) > 0.0) {
|
if (collision_state.floor && !collision_state.wall) {
|
||||||
|
// Slide using the intersection between the motion plane and the floor plane,
|
||||||
|
// in order to keep the direction intact.
|
||||||
|
real_t motion_length = slide_motion.length();
|
||||||
|
slide_motion = up_direction.cross(result.remainder).cross(floor_normal);
|
||||||
|
|
||||||
|
// Keep the length from default slide to change speed in slopes by default,
|
||||||
|
// when constant speed is not enabled.
|
||||||
|
slide_motion.normalize();
|
||||||
|
slide_motion *= motion_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slide_motion.dot(motion_velocity) > 0.0) {
|
||||||
motion = slide_motion;
|
motion = slide_motion;
|
||||||
} else {
|
} else {
|
||||||
motion = Vector3();
|
motion = Vector3();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slide_on_ceiling && result_state.ceiling) {
|
if (slide_on_ceiling && result_state.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(collision.normal);
|
motion_velocity = motion_velocity.slide(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1326,18 +1340,19 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
|
|||||||
else {
|
else {
|
||||||
motion = result.remainder;
|
motion = result.remainder;
|
||||||
if (result_state.ceiling && !slide_on_ceiling && vel_dir_facing_up) {
|
if (result_state.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply Constant Speed.
|
|
||||||
if (p_was_on_floor && floor_constant_speed && collision_state.floor && !motion.is_equal_approx(Vector3())) {
|
|
||||||
motion = motion.normalized() * MAX(0, (motion_slide_up.length() - result.travel.slide(up_direction).length() - total_travel.slide(up_direction).length()));
|
|
||||||
}
|
|
||||||
|
|
||||||
total_travel += result.travel;
|
total_travel += result.travel;
|
||||||
|
|
||||||
|
// Apply Constant Speed.
|
||||||
|
if (p_was_on_floor && floor_constant_speed && can_apply_constant_speed && collision_state.floor && !motion.is_equal_approx(Vector3())) {
|
||||||
|
Vector3 travel_slide_up = total_travel.slide(up_direction);
|
||||||
|
motion = motion.normalized() * MAX(0, (motion_slide_up.length() - travel_slide_up.length()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// When you move forward in a downward slope you don’t collide because you will be in the air.
|
// 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.
|
// This test ensures that constant speed is applied, only if the player is still on the ground after the snap is applied.
|
||||||
@ -1348,34 +1363,34 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
|
|||||||
gt.origin = gt.origin - result.travel;
|
gt.origin = gt.origin - result.travel;
|
||||||
set_global_transform(gt);
|
set_global_transform(gt);
|
||||||
|
|
||||||
Vector3 motion_slide_norm = motion.slide(prev_floor_normal).normalized();
|
// Slide using the intersection between the motion plane and the floor plane,
|
||||||
|
// in order to keep the direction intact.
|
||||||
|
Vector3 motion_slide_norm = up_direction.cross(motion).cross(prev_floor_normal);
|
||||||
|
motion_slide_norm.normalize();
|
||||||
|
|
||||||
motion = motion_slide_norm * (motion_slide_up.length());
|
motion = motion_slide_norm * (motion_slide_up.length());
|
||||||
collided = true;
|
collided = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
can_apply_constant_speed = !can_apply_constant_speed && !sliding_enabled;
|
|
||||||
sliding_enabled = true;
|
|
||||||
first_slide = false;
|
|
||||||
|
|
||||||
if (!motion.is_equal_approx(Vector3())) {
|
|
||||||
last_motion = motion;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!collided || motion.is_equal_approx(Vector3())) {
|
if (!collided || motion.is_equal_approx(Vector3())) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
can_apply_constant_speed = !can_apply_constant_speed && !sliding_enabled;
|
||||||
|
sliding_enabled = true;
|
||||||
|
first_slide = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_snap_on_floor(p_was_on_floor, vel_dir_facing_up);
|
_snap_on_floor(p_was_on_floor, vel_dir_facing_up);
|
||||||
|
|
||||||
// Reset the gravity accumulation when touching the ground.
|
// Reset the gravity accumulation when touching the ground.
|
||||||
if (collision_state.floor && !vel_dir_facing_up) {
|
if (collision_state.floor && !vel_dir_facing_up) {
|
||||||
linear_velocity = linear_velocity.slide(up_direction);
|
motion_velocity = motion_velocity.slide(up_direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterBody3D::_move_and_slide_free(double p_delta) {
|
void CharacterBody3D::_move_and_slide_free(double p_delta) {
|
||||||
Vector3 motion = linear_velocity * p_delta;
|
Vector3 motion = motion_velocity * p_delta;
|
||||||
|
|
||||||
platform_rid = RID();
|
platform_rid = RID();
|
||||||
floor_normal = Vector3();
|
floor_normal = Vector3();
|
||||||
@ -1386,6 +1401,7 @@ void CharacterBody3D::_move_and_slide_free(double p_delta) {
|
|||||||
PhysicsServer3D::MotionResult result;
|
PhysicsServer3D::MotionResult result;
|
||||||
|
|
||||||
bool collided = move_and_collide(motion, result, margin, false, 1, false);
|
bool collided = move_and_collide(motion, result, margin, false, 1, false);
|
||||||
|
last_motion = result.travel;
|
||||||
|
|
||||||
if (collided) {
|
if (collided) {
|
||||||
motion_results.push_back(result);
|
motion_results.push_back(result);
|
||||||
@ -1393,7 +1409,12 @@ void CharacterBody3D::_move_and_slide_free(double p_delta) {
|
|||||||
CollisionState result_state;
|
CollisionState result_state;
|
||||||
_set_collision_direction(result, result_state);
|
_set_collision_direction(result, result_state);
|
||||||
|
|
||||||
if (wall_min_slide_angle != 0 && Math::acos(wall_normal.dot(-linear_velocity.normalized())) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) {
|
if (result.remainder.is_equal_approx(Vector3())) {
|
||||||
|
motion = Vector3();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wall_min_slide_angle != 0 && Math::acos(wall_normal.dot(-motion_velocity.normalized())) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) {
|
||||||
motion = Vector3();
|
motion = Vector3();
|
||||||
if (result.travel.length() < margin + CMP_EPSILON) {
|
if (result.travel.length() < margin + CMP_EPSILON) {
|
||||||
Transform3D gt = get_global_transform();
|
Transform3D gt = get_global_transform();
|
||||||
@ -1407,16 +1428,16 @@ void CharacterBody3D::_move_and_slide_free(double p_delta) {
|
|||||||
motion = result.remainder.slide(wall_normal);
|
motion = result.remainder.slide(wall_normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (motion.dot(linear_velocity) <= 0.0) {
|
if (motion.dot(motion_velocity) <= 0.0) {
|
||||||
motion = Vector3();
|
motion = Vector3();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
first_slide = false;
|
|
||||||
|
|
||||||
if (!collided || motion.is_equal_approx(Vector3())) {
|
if (!collided || motion.is_equal_approx(Vector3())) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
first_slide = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1568,12 +1589,12 @@ real_t CharacterBody3D::get_safe_margin() const {
|
|||||||
return margin;
|
return margin;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 CharacterBody3D::get_linear_velocity() const {
|
const Vector3 &CharacterBody3D::get_motion_velocity() const {
|
||||||
return linear_velocity;
|
return motion_velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterBody3D::set_linear_velocity(const Vector3 &p_velocity) {
|
void CharacterBody3D::set_motion_velocity(const Vector3 &p_velocity) {
|
||||||
linear_velocity = p_velocity;
|
motion_velocity = p_velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharacterBody3D::is_on_floor() const {
|
bool CharacterBody3D::is_on_floor() const {
|
||||||
@ -1600,15 +1621,15 @@ bool CharacterBody3D::is_on_ceiling_only() const {
|
|||||||
return collision_state.ceiling && !collision_state.floor && !collision_state.wall;
|
return collision_state.ceiling && !collision_state.floor && !collision_state.wall;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 CharacterBody3D::get_floor_normal() const {
|
const Vector3 &CharacterBody3D::get_floor_normal() const {
|
||||||
return floor_normal;
|
return floor_normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 CharacterBody3D::get_wall_normal() const {
|
const Vector3 &CharacterBody3D::get_wall_normal() const {
|
||||||
return wall_normal;
|
return wall_normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 CharacterBody3D::get_last_motion() const {
|
const Vector3 &CharacterBody3D::get_last_motion() const {
|
||||||
return last_motion;
|
return last_motion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1616,19 +1637,23 @@ Vector3 CharacterBody3D::get_position_delta() const {
|
|||||||
return get_transform().origin - previous_position;
|
return get_transform().origin - previous_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 CharacterBody3D::get_real_velocity() const {
|
const Vector3 &CharacterBody3D::get_real_velocity() const {
|
||||||
return real_velocity;
|
return real_velocity;
|
||||||
};
|
}
|
||||||
|
|
||||||
real_t CharacterBody3D::get_floor_angle(const Vector3 &p_up_direction) const {
|
real_t CharacterBody3D::get_floor_angle(const Vector3 &p_up_direction) const {
|
||||||
ERR_FAIL_COND_V(p_up_direction == Vector3(), 0);
|
ERR_FAIL_COND_V(p_up_direction == Vector3(), 0);
|
||||||
return Math::acos(floor_normal.dot(p_up_direction));
|
return Math::acos(floor_normal.dot(p_up_direction));
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 CharacterBody3D::get_platform_velocity() const {
|
const Vector3 &CharacterBody3D::get_platform_velocity() const {
|
||||||
return platform_velocity;
|
return platform_velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3 CharacterBody3D::get_linear_velocity() const {
|
||||||
|
return get_real_velocity();
|
||||||
|
}
|
||||||
|
|
||||||
int CharacterBody3D::get_slide_collision_count() const {
|
int CharacterBody3D::get_slide_collision_count() const {
|
||||||
return motion_results.size();
|
return motion_results.size();
|
||||||
}
|
}
|
||||||
@ -1783,8 +1808,8 @@ void CharacterBody3D::_notification(int p_what) {
|
|||||||
void CharacterBody3D::_bind_methods() {
|
void CharacterBody3D::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody3D::move_and_slide);
|
ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody3D::move_and_slide);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &CharacterBody3D::set_linear_velocity);
|
ClassDB::bind_method(D_METHOD("set_motion_velocity", "motion_velocity"), &CharacterBody3D::set_motion_velocity);
|
||||||
ClassDB::bind_method(D_METHOD("get_linear_velocity"), &CharacterBody3D::get_linear_velocity);
|
ClassDB::bind_method(D_METHOD("get_motion_velocity"), &CharacterBody3D::get_motion_velocity);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody3D::set_safe_margin);
|
ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody3D::set_safe_margin);
|
||||||
ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin);
|
ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin);
|
||||||
@ -1837,7 +1862,7 @@ void CharacterBody3D::_bind_methods() {
|
|||||||
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::VECTOR3, "up_direction"), "set_up_direction", "get_up_direction");
|
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_direction"), "set_up_direction", "get_up_direction");
|
||||||
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::VECTOR3, "linear_velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_linear_velocity", "get_linear_velocity");
|
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion_velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_motion_velocity", "get_motion_velocity");
|
||||||
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_GROUP("Free Mode", "free_mode_");
|
ADD_GROUP("Free Mode", "free_mode_");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle");
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle");
|
||||||
|
@ -328,8 +328,8 @@ public:
|
|||||||
};
|
};
|
||||||
bool move_and_slide();
|
bool move_and_slide();
|
||||||
|
|
||||||
virtual Vector3 get_linear_velocity() const override;
|
const Vector3 &get_motion_velocity() const;
|
||||||
void set_linear_velocity(const Vector3 &p_velocity);
|
void set_motion_velocity(const Vector3 &p_velocity);
|
||||||
|
|
||||||
bool is_on_floor() const;
|
bool is_on_floor() const;
|
||||||
bool is_on_floor_only() const;
|
bool is_on_floor_only() const;
|
||||||
@ -337,13 +337,15 @@ 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;
|
||||||
Vector3 get_last_motion() const;
|
const Vector3 &get_last_motion() const;
|
||||||
Vector3 get_position_delta() const;
|
Vector3 get_position_delta() const;
|
||||||
Vector3 get_floor_normal() const;
|
const Vector3 &get_floor_normal() const;
|
||||||
Vector3 get_wall_normal() const;
|
const Vector3 &get_wall_normal() const;
|
||||||
Vector3 get_real_velocity() const;
|
const Vector3 &get_real_velocity() const;
|
||||||
real_t get_floor_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
|
real_t get_floor_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
|
||||||
Vector3 get_platform_velocity() const;
|
const Vector3 &get_platform_velocity() const;
|
||||||
|
|
||||||
|
virtual Vector3 get_linear_velocity() const override;
|
||||||
|
|
||||||
int get_slide_collision_count() const;
|
int get_slide_collision_count() const;
|
||||||
PhysicsServer3D::MotionResult get_slide_collision(int p_bounce) const;
|
PhysicsServer3D::MotionResult get_slide_collision(int p_bounce) const;
|
||||||
@ -379,7 +381,7 @@ private:
|
|||||||
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 = 6;
|
int max_slides = 6;
|
||||||
int platform_layer;
|
int platform_layer = 0;
|
||||||
RID platform_rid;
|
RID platform_rid;
|
||||||
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;
|
||||||
@ -387,7 +389,7 @@ private:
|
|||||||
real_t floor_max_angle = Math::deg2rad((real_t)45.0);
|
real_t floor_max_angle = Math::deg2rad((real_t)45.0);
|
||||||
real_t wall_min_slide_angle = Math::deg2rad((real_t)15.0);
|
real_t wall_min_slide_angle = Math::deg2rad((real_t)15.0);
|
||||||
Vector3 up_direction = Vector3(0.0, 1.0, 0.0);
|
Vector3 up_direction = Vector3(0.0, 1.0, 0.0);
|
||||||
Vector3 linear_velocity;
|
Vector3 motion_velocity;
|
||||||
Vector3 floor_normal;
|
Vector3 floor_normal;
|
||||||
Vector3 wall_normal;
|
Vector3 wall_normal;
|
||||||
Vector3 last_motion;
|
Vector3 last_motion;
|
||||||
|
Loading…
Reference in New Issue
Block a user