Skip to content

Commit

Permalink
Improved logic for CharacterBody collision recovery depth
Browse files Browse the repository at this point in the history
Allows 2D character controller to work without applying gravity when
touching the ground (also more safely in 3D), and collision detection
is more flexible with different safe margin values.

Character body motion changes in 2D and 3D:
-Recovery only for depth > min contact depth to help with collision
detection consistency (rest info could be lost if recovery was too much)
-Adaptive min contact depth (based on margin) instead of space parameter

Extra CharacterBody changes:
-2D: apply changes made in 3D for stop on slope and floor snap that help
fixing some jittering cases
-3D: fix minor inconsistencies in stop on slope and floor snap logic
  • Loading branch information
pouleyKetchoupp committed Sep 27, 2021
1 parent c1e6c2c commit bf523a2
Show file tree
Hide file tree
Showing 14 changed files with 49 additions and 49 deletions.
2 changes: 1 addition & 1 deletion doc/classes/CharacterBody2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
<member name="floor_max_angle" type="float" setter="set_floor_max_angle" getter="get_floor_max_angle" default="0.785398">
Maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. The default value equals 45 degrees.
</member>
<member name="floor_snap_length" type="float" setter="set_floor_snap_length" getter="get_floor_snap_length" default="0.0">
<member name="floor_snap_length" type="float" setter="set_floor_snap_length" getter="get_floor_snap_length" default="1.0">
Sets a snapping distance. When set to a value different from [code]0.0[/code], the body is kept attached to slopes when calling [method move_and_slide]. The snapping vector is determined by the given distance along the opposite direction of the [member up_direction].
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>
Expand Down
2 changes: 0 additions & 2 deletions doc/classes/PhysicsServer2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -851,8 +851,6 @@
<constant name="SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS" value="6" enum="SpaceParameter">
Constant to set/get the default solver bias for all physics constraints. A solver bias is a factor controlling how much two objects "rebound", after violating a constraint, to avoid leaving them in that state because of numerical imprecision.
</constant>
<constant name="SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH" value="7" enum="SpaceParameter">
</constant>
<constant name="SHAPE_WORLD_BOUNDARY" value="0" enum="ShapeType">
This is the constant for creating world boundary shapes. A world boundary shape is an [i]infinite[/i] line with an origin point, and a normal. Thus, it can be used for front/behind checks.
</constant>
Expand Down
2 changes: 0 additions & 2 deletions doc/classes/PhysicsServer3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1361,8 +1361,6 @@
<constant name="SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS" value="7" enum="SpaceParameter">
Constant to set/get the default solver bias for all physics constraints. A solver bias is a factor controlling how much two objects "rebound", after violating a constraint, to avoid leaving them in that state because of numerical imprecision.
</constant>
<constant name="SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH" value="8" enum="SpaceParameter">
</constant>
<constant name="BODY_AXIS_LINEAR_X" value="1" enum="BodyAxis">
</constant>
<constant name="BODY_AXIS_LINEAR_Y" value="2" enum="BodyAxis">
Expand Down
22 changes: 13 additions & 9 deletions scene/2d/physics_body_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1089,9 +1089,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo

if (on_floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) {
Transform2D gt = get_global_transform();
if (result.travel.length() > margin) {
gt.elements[2] -= result.travel.slide(up_direction);
} else {
if (result.travel.length() <= margin + CMP_EPSILON) {
gt.elements[2] -= result.travel;
}
set_global_transform(gt);
Expand All @@ -1110,7 +1108,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
// Avoid to move forward on a wall if floor_block_on_wall is true.
if (p_was_on_floor && !on_floor && !vel_dir_facing_up) {
// If the movement is large the body can be prevented from reaching the walls.
if (result.travel.length() <= margin) {
if (result.travel.length() <= margin + CMP_EPSILON) {
// Cancels the motion.
Transform2D gt = get_global_transform();
gt.elements[2] -= result.travel;
Expand Down Expand Up @@ -1239,13 +1237,16 @@ void CharacterBody2D::_move_and_slide_free(double p_delta) {
}

void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) {
if (Math::is_equal_approx(floor_snap_length, 0) || on_floor || !was_on_floor || vel_dir_facing_up) {
if (on_floor || !was_on_floor || vel_dir_facing_up) {
return;
}

// Snap by at least collision margin to keep floor state consistent.
real_t length = MAX(floor_snap_length, margin);

Transform2D gt = get_global_transform();
PhysicsServer2D::MotionResult result;
if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false, true)) {
if (move_and_collide(-up_direction * length, result, margin, true, false, true)) {
bool apply = true;
if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
on_floor = true;
Expand Down Expand Up @@ -1273,12 +1274,15 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up)
}

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) {
if (up_direction == Vector2() || on_floor || !was_on_floor || vel_dir_facing_up) {
return false;
}

// Snap by at least collision margin to keep floor state consistent.
real_t length = MAX(floor_snap_length, margin);

PhysicsServer2D::MotionResult result;
if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false, true)) {
if (move_and_collide(-up_direction * length, result, margin, true, false, true)) {
if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
return true;
}
Expand Down Expand Up @@ -1566,7 +1570,7 @@ void CharacterBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,1000,0.1"), "set_floor_snap_length", "get_floor_snap_length");
ADD_PROPERTY(PropertyInfo(Variant::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_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");
Expand Down
2 changes: 1 addition & 1 deletion scene/2d/physics_body_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ class CharacterBody2D : public PhysicsBody2D {
int max_slides = 4;
int platform_layer;
real_t floor_max_angle = Math::deg2rad((real_t)45.0);
real_t floor_snap_length = 0;
real_t floor_snap_length = 1;
real_t free_mode_min_slide_angle = Math::deg2rad((real_t)15.0);
Vector2 up_direction = Vector2(0.0, -1.0);
uint32_t moving_platform_floor_layers = UINT32_MAX;
Expand Down
14 changes: 9 additions & 5 deletions scene/3d/physics_body_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1145,8 +1145,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo

if (collision_state.floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) {
Transform3D gt = get_global_transform();
real_t travel_total = result.travel.length();
if (travel_total <= margin + CMP_EPSILON) {
if (result.travel.length() <= margin + CMP_EPSILON) {
gt.origin -= result.travel;
}
set_global_transform(gt);
Expand Down Expand Up @@ -1185,7 +1184,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
Transform3D gt = get_global_transform();
real_t travel_total = result.travel.length();
real_t cancel_dist_max = MIN(0.1, margin * 20);
if (travel_total < margin + CMP_EPSILON) {
if (travel_total <= margin + CMP_EPSILON) {
gt.origin -= result.travel;
} else if (travel_total < cancel_dist_max) { // If the movement is large the body can be prevented from reaching the walls.
gt.origin -= result.travel.slide(up_direction);
Expand Down Expand Up @@ -1376,7 +1375,9 @@ void CharacterBody3D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up)
return;
}

// Snap by at least collision margin to keep floor state consistent.
real_t length = MAX(floor_snap_length, margin);

Transform3D gt = get_global_transform();
PhysicsServer3D::MotionResult result;
if (move_and_collide(-up_direction * length, result, margin, true, 4, false, true)) {
Expand All @@ -1402,12 +1403,15 @@ void CharacterBody3D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up)
}

bool CharacterBody3D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facing_up) {
if (Math::is_zero_approx(floor_snap_length) || up_direction == Vector3() || collision_state.floor || !was_on_floor || vel_dir_facing_up) {
if (up_direction == Vector3() || collision_state.floor || !was_on_floor || vel_dir_facing_up) {
return false;
}

// Snap by at least collision margin to keep floor state consistent.
real_t length = MAX(floor_snap_length, margin);

PhysicsServer3D::MotionResult result;
if (move_and_collide(-up_direction * floor_snap_length, result, margin, true, 4, false, true)) {
if (move_and_collide(-up_direction * length, result, margin, true, 4, false, true)) {
CollisionState result_state;
// Don't apply direction for any type.
_set_collision_direction(result, result_state, CollisionState());
Expand Down
24 changes: 13 additions & 11 deletions servers/physics_2d/space_2d_sw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
#include "core/os/os.h"
#include "core/templates/pair.h"
#include "physics_server_2d_sw.h"

#define TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR 0.05

_FORCE_INLINE_ static bool _can_collide_with(CollisionObject2DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
if (!(p_object->get_collision_layer() & p_collision_mask)) {
return false;
Expand Down Expand Up @@ -435,6 +438,8 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh
Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, 0);

real_t min_contact_depth = p_margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;

Rect2 aabb = p_shape_xform.xform(shape->get_aabb());
aabb = aabb.merge(Rect2(aabb.position + p_motion, aabb.size)); //motion
aabb = aabb.grow(p_margin);
Expand All @@ -445,7 +450,7 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh
rcd.best_len = 0;
rcd.best_object = nullptr;
rcd.best_shape = 0;
rcd.min_allowed_depth = space->test_motion_min_contact_depth;
rcd.min_allowed_depth = min_contact_depth;

for (int i = 0; i < amount; i++) {
if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) {
Expand Down Expand Up @@ -569,6 +574,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
ExcludedShapeSW excluded_shape_pairs[max_excluded_shape_pairs];
int excluded_shape_pair_count = 0;

real_t min_contact_depth = p_margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;

real_t motion_length = p_motion.length();
Vector2 motion_normal = p_motion / motion_length;

Expand Down Expand Up @@ -671,6 +678,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
break;
}

recovered = true;

Vector2 recover_motion;
for (int i = 0; i < cbk.amount; i++) {
Vector2 a = sr[i * 2 + 0];
Expand All @@ -682,9 +691,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co

// Compute depth on recovered motion.
real_t depth = n.dot(a + recover_motion) - d;
if (depth > 0.0) {
if (depth > min_contact_depth + CMP_EPSILON) {
// Only recover if there is penetration.
recover_motion -= n * depth * 0.4;
recover_motion -= n * (depth - min_contact_depth) * 0.4;
}
}

Expand All @@ -693,8 +702,6 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
break;
}

recovered = true;

body_transform.elements[2] += recover_motion;
body_aabb.position += recover_motion;

Expand Down Expand Up @@ -870,7 +877,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
rcd.best_shape = 0;

// Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth);
rcd.min_allowed_depth = MIN(motion_length, min_contact_depth);

int from_shape = best_shape != -1 ? best_shape : 0;
int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count();
Expand Down Expand Up @@ -1141,9 +1148,6 @@ void Space2DSW::set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_valu
case PhysicsServer2D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
constraint_bias = p_value;
break;
case PhysicsServer2D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH:
test_motion_min_contact_depth = p_value;
break;
}
}

Expand All @@ -1163,8 +1167,6 @@ real_t Space2DSW::get_param(PhysicsServer2D::SpaceParameter p_param) const {
return body_time_to_sleep;
case PhysicsServer2D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
return constraint_bias;
case PhysicsServer2D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH:
return test_motion_min_contact_depth;
}
return 0;
}
Expand Down
1 change: 0 additions & 1 deletion servers/physics_2d/space_2d_sw.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ class Space2DSW {
real_t contact_max_separation = 1.5;
real_t contact_max_allowed_penetration = 0.3;
real_t constraint_bias = 0.2;
real_t test_motion_min_contact_depth = 0.005;

enum {
INTERSECTION_QUERY_MAX = 2048
Expand Down
24 changes: 12 additions & 12 deletions servers/physics_3d/space_3d_sw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#include "core/config/project_settings.h"
#include "physics_server_3d_sw.h"

#define TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR 0.05

_FORCE_INLINE_ static bool _can_collide_with(CollisionObject3DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
if (!(p_object->get_collision_layer() & p_collision_mask)) {
return false;
Expand Down Expand Up @@ -488,13 +490,15 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform3D &p_sh
Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, 0);

real_t min_contact_depth = p_margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;

AABB aabb = p_shape_xform.xform(shape->get_aabb());
aabb = aabb.grow(p_margin);

int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);

_RestCallbackData rcd;
rcd.min_allowed_depth = space->test_motion_min_contact_depth;
rcd.min_allowed_depth = min_contact_depth;

for (int i = 0; i < amount; i++) {
if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) {
Expand Down Expand Up @@ -658,6 +662,8 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb));
body_aabb = body_aabb.grow(p_margin);

real_t min_contact_depth = p_margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;

real_t motion_length = p_motion.length();
Vector3 motion_normal = p_motion / motion_length;

Expand Down Expand Up @@ -711,8 +717,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
break;
}

Vector3 recover_motion;
recovered = true;

Vector3 recover_motion;
for (int i = 0; i < cbk.amount; i++) {
Vector3 a = sr[i * 2 + 0];
Vector3 b = sr[i * 2 + 1];
Expand All @@ -723,9 +730,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co

// Compute depth on recovered motion.
real_t depth = n.dot(a + recover_motion) - d;
if (depth > 0.0) {
if (depth > min_contact_depth + CMP_EPSILON) {
// Only recover if there is penetration.
recover_motion -= n * depth * 0.4;
recover_motion -= n * (depth - min_contact_depth) * 0.4;
}
}

Expand All @@ -734,8 +741,6 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
break;
}

recovered = true;

body_transform.origin += recover_motion;
body_aabb.position += recover_motion;

Expand Down Expand Up @@ -889,7 +894,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
}

// Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth);
rcd.min_allowed_depth = MIN(motion_length, min_contact_depth);

int from_shape = best_shape != -1 ? best_shape : 0;
int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count();
Expand Down Expand Up @@ -1158,9 +1163,6 @@ void Space3DSW::set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_valu
case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
constraint_bias = p_value;
break;
case PhysicsServer3D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH:
test_motion_min_contact_depth = p_value;
break;
}
}

Expand All @@ -1182,8 +1184,6 @@ real_t Space3DSW::get_param(PhysicsServer3D::SpaceParameter p_param) const {
return body_angular_velocity_damp_ratio;
case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
return constraint_bias;
case PhysicsServer3D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH:
return test_motion_min_contact_depth;
}
return 0;
}
Expand Down
1 change: 0 additions & 1 deletion servers/physics_3d/space_3d_sw.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ class Space3DSW {
real_t contact_max_separation = 0.05;
real_t contact_max_allowed_penetration = 0.01;
real_t constraint_bias = 0.01;
real_t test_motion_min_contact_depth = 0.00001;

enum {
INTERSECTION_QUERY_MAX = 2048
Expand Down
1 change: 0 additions & 1 deletion servers/physics_server_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,6 @@ void PhysicsServer2D::_bind_methods() {
BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD);
BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP);
BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS);
BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH);

BIND_ENUM_CONSTANT(SHAPE_WORLD_BOUNDARY);
BIND_ENUM_CONSTANT(SHAPE_SEPARATION_RAY);
Expand Down
1 change: 0 additions & 1 deletion servers/physics_server_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ class PhysicsServer2D : public Object {
SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD,
SPACE_PARAM_BODY_TIME_TO_SLEEP,
SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS,
SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH,
};

virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0;
Expand Down
1 change: 0 additions & 1 deletion servers/physics_server_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,6 @@ void PhysicsServer3D::_bind_methods() {
BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP);
BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO);
BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS);
BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH);

BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_X);
BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_Y);
Expand Down
1 change: 0 additions & 1 deletion servers/physics_server_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,6 @@ class PhysicsServer3D : public Object {
SPACE_PARAM_BODY_TIME_TO_SLEEP,
SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO,
SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS,
SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH
};

virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0;
Expand Down

0 comments on commit bf523a2

Please sign in to comment.