@@ -1080,8 +1080,6 @@ void RigidBody3D::_reload_physics_characteristics() {
10801080#define FLOOR_ANGLE_THRESHOLD 0.01
10811081
10821082bool CharacterBody3D::move_and_slide () {
1083- Vector3 body_velocity_normal = linear_velocity.normalized ();
1084-
10851083 bool was_on_floor = on_floor;
10861084
10871085 // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
@@ -1111,7 +1109,7 @@ bool CharacterBody3D::move_and_slide() {
11111109 floor_normal = Vector3 ();
11121110 floor_velocity = Vector3 ();
11131111
1114- if (current_floor_velocity != Vector3 () && on_floor_body.is_valid ()) {
1112+ if (!current_floor_velocity. is_equal_approx ( Vector3 () ) && on_floor_body.is_valid ()) {
11151113 PhysicsServer3D::MotionResult floor_result;
11161114 Set<RID> exclude;
11171115 exclude.insert (on_floor_body);
@@ -1130,39 +1128,35 @@ bool CharacterBody3D::move_and_slide() {
11301128
11311129 for (int iteration = 0 ; iteration < max_slides; ++iteration) {
11321130 PhysicsServer3D::MotionResult result;
1133- bool found_collision = false ;
1134-
11351131 bool collided = move_and_collide (motion, result, margin, false , !sliding_enabled);
1136- if (!collided) {
1137- motion = Vector3 (); // clear because no collision happened and motion completed
1138- } else {
1139- found_collision = true ;
1140-
1132+ if (collided) {
11411133 motion_results.push_back (result);
11421134 _set_collision_direction (result);
11431135
1144- if (on_floor && floor_stop_on_slope) {
1145- if ((body_velocity_normal + up_direction).length () < 0.01 ) {
1146- Transform3D gt = get_global_transform ();
1147- if (result.travel .length () > margin) {
1148- gt.origin -= result.travel .slide (up_direction);
1149- } else {
1150- gt.origin -= result.travel ;
1151- }
1152- set_global_transform (gt);
1153- linear_velocity = Vector3 ();
1154- return true ;
1136+ if (on_floor && floor_stop_on_slope && (linear_velocity.normalized () + up_direction).length () < 0.01 ) {
1137+ Transform3D gt = get_global_transform ();
1138+ if (result.travel .length () > margin) {
1139+ gt.origin -= result.travel .slide (up_direction);
1140+ } else {
1141+ gt.origin -= result.travel ;
11551142 }
1143+ set_global_transform (gt);
1144+ linear_velocity = Vector3 ();
1145+ motion = Vector3 ();
1146+ break ;
11561147 }
11571148
1158- if (sliding_enabled || !on_floor) {
1159- motion = result.remainder .slide (result.collision_normal );
1160- linear_velocity = linear_velocity.slide (result.collision_normal );
1149+ if (result.remainder .is_equal_approx (Vector3 ())) {
1150+ motion = Vector3 ();
1151+ break ;
1152+ }
11611153
1162- for (int j = 0 ; j < 3 ; j++) {
1163- if (locked_axis & (1 << j)) {
1164- linear_velocity[j] = 0.0 ;
1165- }
1154+ if (sliding_enabled || !on_floor) {
1155+ Vector3 slide_motion = result.remainder .slide (result.collision_normal );
1156+ if (slide_motion.dot (linear_velocity) > 0.0 ) {
1157+ motion = slide_motion;
1158+ } else {
1159+ motion = Vector3 ();
11661160 }
11671161 } else {
11681162 motion = result.remainder ;
@@ -1171,12 +1165,12 @@ bool CharacterBody3D::move_and_slide() {
11711165
11721166 sliding_enabled = true ;
11731167
1174- if (!found_collision || motion == Vector3 ()) {
1168+ if (!collided || motion. is_equal_approx ( Vector3 () )) {
11751169 break ;
11761170 }
11771171 }
11781172
1179- if (was_on_floor && snap != Vector3 ()) {
1173+ if (was_on_floor && !on_floor && !snap. is_equal_approx ( Vector3 () )) {
11801174 // Apply snap.
11811175 Transform3D gt = get_global_transform ();
11821176 PhysicsServer3D::MotionResult result;
@@ -1213,6 +1207,11 @@ bool CharacterBody3D::move_and_slide() {
12131207 linear_velocity += current_floor_velocity;
12141208 }
12151209
1210+ // Reset the gravity accumulation when touching the ground.
1211+ if (on_floor && linear_velocity.dot (up_direction) <= 0 ) {
1212+ linear_velocity = linear_velocity.slide (up_direction);
1213+ }
1214+
12161215 return motion_results.size () > 0 ;
12171216}
12181217
0 commit comments