Skip to content

Commit

Permalink
Safe margin cleanup
Browse files Browse the repository at this point in the history
Safe margin property on CharacterBody only, used as argument in
move_and_collide.

Removed kinematic_safe_margin in 3D physics server, not really useful
and now harmonized with 2D.
  • Loading branch information
pouleyKetchoupp committed Jun 4, 2021
1 parent 6582255 commit b2bd9f4
Show file tree
Hide file tree
Showing 17 changed files with 90 additions and 134 deletions.
6 changes: 6 additions & 0 deletions doc/classes/CharacterBody2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@
</method>
</methods>
<members>
<member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.08">
Extra margin used for collision recovery when calling [method move_and_slide].
If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies.
</member>
<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>
Expand Down
6 changes: 6 additions & 0 deletions doc/classes/CharacterBody3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@
</method>
</methods>
<members>
<member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.001">
Extra margin used for collision recovery when calling [method move_and_slide].
If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies.
</member>
<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>
Expand Down
12 changes: 6 additions & 6 deletions doc/classes/PhysicsBody2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@
</argument>
<argument index="3" name="test_only" type="bool" default="false">
</argument>
<argument index="4" name="safe_margin" type="float" default="0.08">
</argument>
<description>
Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision2D], which contains information about the collision.
If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
[code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details).
</description>
</method>
<method name="remove_collision_exception_with">
Expand All @@ -64,19 +67,16 @@
</argument>
<argument index="4" name="collision" type="KinematicCollision2D" default="null">
</argument>
<argument index="5" name="safe_margin" type="float" default="0.08">
</argument>
<description>
Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur.
[code]collision[/code] is an optional object of type [KinematicCollision2D], which contains additional information about the collision (should there be one).
[code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details).
</description>
</method>
</methods>
<members>
<member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.08">
Extra margin used for collision recovery in motion functions (see [method move_and_collide] and [method CharacterBody2D.move_and_slide]).
If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies.
</member>
<member name="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" override="true" default="false" />
</members>
<constants>
Expand Down
12 changes: 6 additions & 6 deletions doc/classes/PhysicsBody3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,12 @@
</argument>
<argument index="3" name="test_only" type="bool" default="false">
</argument>
<argument index="4" name="safe_margin" type="float" default="0.001">
</argument>
<description>
Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision.
If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
[code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details).
</description>
</method>
<method name="remove_collision_exception_with">
Expand Down Expand Up @@ -84,9 +87,12 @@
</argument>
<argument index="4" name="collision" type="KinematicCollision3D" default="null">
</argument>
<argument index="5" name="safe_margin" type="float" default="0.001">
</argument>
<description>
Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur.
[code]collision[/code] is an optional object of type [KinematicCollision3D], which contains additional information about the collision (should there be one).
[code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details).
</description>
</method>
</methods>
Expand All @@ -109,12 +115,6 @@
<member name="axis_lock_linear_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
Lock the body's linear movement in the Z axis.
</member>
<member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.001">
Extra margin used for collision recovery in motion functions (see [method move_and_collide] and [method CharacterBody3D.move_and_slide]).
If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies.
</member>
</members>
<constants>
</constants>
Expand Down
18 changes: 0 additions & 18 deletions doc/classes/PhysicsServer3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -443,14 +443,6 @@
Returns the [PhysicsDirectBodyState3D] of the body.
</description>
</method>
<method name="body_get_kinematic_safe_margin" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="body" type="RID">
</argument>
<description>
</description>
</method>
<method name="body_get_max_contacts_reported" qualifiers="const">
<return type="int">
</return>
Expand Down Expand Up @@ -661,16 +653,6 @@
Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]).
</description>
</method>
<method name="body_set_kinematic_safe_margin">
<return type="void">
</return>
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="margin" type="float">
</argument>
<description>
</description>
</method>
<method name="body_set_max_contacts_reported">
<return type="void">
</return>
Expand Down
44 changes: 21 additions & 23 deletions scene/2d/physics_body_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,12 @@
#include "scene/scene_string_names.h"

void PhysicsBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &PhysicsBody2D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false));
ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "collision"), &PhysicsBody2D::test_move, DEFVAL(true), DEFVAL(true), DEFVAL(Variant()));

ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &PhysicsBody2D::set_safe_margin);
ClassDB::bind_method(D_METHOD("get_safe_margin"), &PhysicsBody2D::get_safe_margin);
ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false), DEFVAL(0.08));
ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(true), DEFVAL(true), DEFVAL(Variant()), DEFVAL(0.08));

ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with);
ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody2D::remove_collision_exception_with);

ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
}

PhysicsBody2D::PhysicsBody2D(PhysicsServer2D::BodyMode p_mode) :
Expand All @@ -64,10 +59,10 @@ PhysicsBody2D::~PhysicsBody2D() {
}
}

Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only) {
Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only, real_t p_margin) {
PhysicsServer2D::MotionResult result;

if (move_and_collide(p_motion, p_infinite_inertia, result, p_exclude_raycast_shapes, p_test_only)) {
if (move_and_collide(p_motion, p_infinite_inertia, result, p_margin, p_exclude_raycast_shapes, p_test_only)) {
if (motion_cache.is_null()) {
motion_cache.instance();
motion_cache->owner = this;
Expand All @@ -81,12 +76,12 @@ Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_i
return Ref<KinematicCollision2D>();
}

bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, PhysicsServer2D::MotionResult &r_result, bool p_exclude_raycast_shapes, bool p_test_only) {
bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only) {
if (is_only_update_transform_changes_enabled()) {
ERR_PRINT("Move functions do not work together with 'sync to physics' option. Please read the documentation.");
}
Transform2D gt = get_global_transform();
bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &r_result, p_exclude_raycast_shapes);
bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes);

if (!p_test_only) {
gt.elements[2] += r_result.motion;
Expand All @@ -96,7 +91,7 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_in
return colliding;
}

bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, const Ref<KinematicCollision2D> &r_collision) {
bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) {
ERR_FAIL_COND_V(!is_inside_tree(), false);

PhysicsServer2D::MotionResult *r = nullptr;
Expand All @@ -105,15 +100,7 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion
r = const_cast<PhysicsServer2D::MotionResult *>(&r_collision->result);
}

return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, margin, r, p_exclude_raycast_shapes);
}

void PhysicsBody2D::set_safe_margin(real_t p_margin) {
margin = p_margin;
}

real_t PhysicsBody2D::get_safe_margin() const {
return margin;
return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes);
}

TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() {
Expand Down Expand Up @@ -964,7 +951,7 @@ Vector2 CharacterBody2D::move_and_slide(const Vector2 &p_linear_velocity) {
for (int i = 0; i < 2; ++i) {
bool collided;
if (i == 0) { //collide
collided = move_and_collide(motion, infinite_inertia, result);
collided = move_and_collide(motion, infinite_inertia, result, margin);
if (!collided) {
motion = Vector2(); //clear because no collision happened and motion completed
}
Expand Down Expand Up @@ -1027,7 +1014,7 @@ Vector2 CharacterBody2D::move_and_slide(const Vector2 &p_linear_velocity) {
// Apply snap.
Transform2D gt = get_global_transform();
PhysicsServer2D::MotionResult result;
if (move_and_collide(snap, infinite_inertia, result, false, true)) {
if (move_and_collide(snap, infinite_inertia, result, margin, false, true)) {
bool apply = true;
if (up_direction != Vector2()) {
if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
Expand Down Expand Up @@ -1174,6 +1161,14 @@ void CharacterBody2D::_direct_state_changed(Object *p_state) {
set_notify_local_transform(true);
}

void CharacterBody2D::set_safe_margin(real_t p_margin) {
margin = p_margin;
}

real_t CharacterBody2D::get_safe_margin() const {
return margin;
}

bool CharacterBody2D::is_stop_on_slope_enabled() const {
return stop_on_slope;
}
Expand Down Expand Up @@ -1249,6 +1244,8 @@ void CharacterBody2D::_notification(int p_what) {
void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity"), &CharacterBody2D::move_and_slide);

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("is_stop_on_slope_enabled"), &CharacterBody2D::is_stop_on_slope_enabled);
ClassDB::bind_method(D_METHOD("set_stop_on_slope_enabled", "enabled"), &CharacterBody2D::set_stop_on_slope_enabled);
ClassDB::bind_method(D_METHOD("is_infinite_inertia_enabled"), &CharacterBody2D::is_infinite_inertia_enabled);
Expand Down Expand Up @@ -1281,6 +1278,7 @@ void CharacterBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction");

ADD_PROPERTY(PropertyInfo(Variant::BOOL, "motion/sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
}

CharacterBody2D::CharacterBody2D() :
Expand Down
15 changes: 8 additions & 7 deletions scene/2d/physics_body_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,13 @@ class PhysicsBody2D : public CollisionObject2D {
static void _bind_methods();
PhysicsBody2D(PhysicsServer2D::BodyMode p_mode);

real_t margin = 0.08;
Ref<KinematicCollision2D> motion_cache;

Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false, real_t p_margin = 0.08);

public:
bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, PhysicsServer2D::MotionResult &r_result, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
bool test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>());

void set_safe_margin(real_t p_margin);
real_t get_safe_margin() const;
bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
bool test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08);

TypedArray<PhysicsBody2D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
Expand Down Expand Up @@ -263,6 +259,8 @@ class CharacterBody2D : public PhysicsBody2D {
GDCLASS(CharacterBody2D, PhysicsBody2D);

private:
real_t margin = 0.08;

bool stop_on_slope = false;
bool infinite_inertia = true;
int max_slides = 4;
Expand All @@ -288,6 +286,9 @@ class CharacterBody2D : public PhysicsBody2D {
Transform2D last_valid_transform;
void _direct_state_changed(Object *p_state);

void set_safe_margin(real_t p_margin);
real_t get_safe_margin() const;

bool is_stop_on_slope_enabled() const;
void set_stop_on_slope_enabled(bool p_enabled);

Expand Down
Loading

0 comments on commit b2bd9f4

Please sign in to comment.