Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move sync to physics to StaticBody2D #49327

Merged
merged 1 commit into from
Jul 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions doc/classes/CharacterBody2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,6 @@
<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].
</member>
<member name="motion/sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false">
If [code]true[/code], the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method move_and_slide] or [method PhysicsBody2D.move_and_collide] functions.
</member>
<member name="snap" type="Vector2" setter="set_snap" getter="get_snap" default="Vector2(0, 0)">
When set to a value different from [code]Vector2(0, 0)[/code], the body is kept attached to slopes when calling [method move_and_slide].
As long as the [code]snap[/code] vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting [code]snap[/code] to [code]Vector2(0, 0)[/code].
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/StaticBody2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
The physics material override for the body.
If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one.
</member>
<member name="sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false">
If [code]true[/code] and [member kinematic_motion] is enabled, the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method PhysicsBody2D.move_and_collide].
</member>
</members>
<constants>
</constants>
Expand Down
2 changes: 1 addition & 1 deletion scene/2d/collision_object_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class CollisionObject2D : public Node2D {
int total_subshapes = 0;

Map<uint32_t, ShapeData> shapes;
bool only_update_transform_changes = false; //this is used for sync physics in CharacterBody2D
bool only_update_transform_changes = false; // This is used for sync to physics.

void _apply_disabled();
void _apply_enabled();
Expand Down
167 changes: 102 additions & 65 deletions scene/2d/physics_body_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,89 @@ void StaticBody2D::set_kinematic_motion_enabled(bool p_enabled) {
set_body_mode(PhysicsServer2D::BODY_MODE_STATIC);
}

#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
update_configuration_warnings();
return;
}
#endif

_update_kinematic_motion();
}

bool StaticBody2D::is_kinematic_motion_enabled() const {
return kinematic_motion;
}

void StaticBody2D::set_sync_to_physics(bool p_enable) {
if (sync_to_physics == p_enable) {
return;
}

sync_to_physics = p_enable;

#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
update_configuration_warnings();
return;
}
#endif

if (kinematic_motion) {
_update_kinematic_motion();
}
}

bool StaticBody2D::is_sync_to_physics_enabled() const {
return sync_to_physics;
}

void StaticBody2D::_direct_state_changed(Object *p_state) {
if (!sync_to_physics) {
return;
}

PhysicsDirectBodyState2D *state = Object::cast_to<PhysicsDirectBodyState2D>(p_state);
ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState2D object as argument");

last_valid_transform = state->get_transform();
set_notify_local_transform(false);
set_global_transform(last_valid_transform);
set_notify_local_transform(true);
}

TypedArray<String> StaticBody2D::get_configuration_warnings() const {
TypedArray<String> warnings = PhysicsBody2D::get_configuration_warnings();

if (sync_to_physics && !kinematic_motion) {
warnings.push_back(TTR("Sync to physics works only when kinematic motion is enabled."));
}

return warnings;
}

void StaticBody2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
last_valid_transform = get_global_transform();
} break;

case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
// Used by sync to physics, send the new transform to the physics...
Transform2D new_transform = get_global_transform();

real_t delta_time = get_physics_process_delta_time();
new_transform.translate(constant_linear_velocity * delta_time);
new_transform.set_rotation(new_transform.get_rotation() + constant_angular_velocity * delta_time);

PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform);

// ... but then revert changes.
set_notify_local_transform(false);
set_global_transform(last_valid_transform);
set_notify_local_transform(true);
} break;

case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
Expand All @@ -247,19 +321,23 @@ void StaticBody2D::_notification(int p_what) {

ERR_FAIL_COND(!kinematic_motion);

real_t delta_time = get_physics_process_delta_time();

Transform2D new_transform = get_global_transform();

real_t delta_time = get_physics_process_delta_time();
new_transform.translate(constant_linear_velocity * delta_time);
new_transform.set_rotation(new_transform.get_rotation() + constant_angular_velocity * delta_time);

PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform);
if (sync_to_physics) {
// Propagate transform change to node.
set_global_transform(new_transform);
} else {
PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform);

// Propagate transform change to node.
set_block_transform_notify(true);
set_global_transform(new_transform);
set_block_transform_notify(false);
// Propagate transform change to node.
set_block_transform_notify(true);
set_global_transform(new_transform);
set_block_transform_notify(false);
}
} break;
}
}
Expand All @@ -276,10 +354,14 @@ void StaticBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody2D::set_physics_material_override);
ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody2D::get_physics_material_override);

ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &StaticBody2D::set_sync_to_physics);
ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &StaticBody2D::is_sync_to_physics_enabled);

ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "kinematic_motion"), "set_kinematic_motion_enabled", "is_kinematic_motion_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled");
}

StaticBody2D::StaticBody2D() :
Expand All @@ -303,14 +385,24 @@ void StaticBody2D::_update_kinematic_motion() {
}
#endif

if (kinematic_motion && sync_to_physics) {
PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &StaticBody2D::_direct_state_changed));
set_only_update_transform_changes(true);
set_notify_local_transform(true);
} else {
PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
set_only_update_transform_changes(false);
set_notify_local_transform(false);
}

bool needs_physics_process = false;
if (kinematic_motion) {
if (!Math::is_zero_approx(constant_angular_velocity) || !constant_linear_velocity.is_equal_approx(Vector2())) {
set_physics_process_internal(true);
return;
needs_physics_process = true;
}
}

set_physics_process_internal(false);
set_physics_process_internal(needs_physics_process);
}

void RigidBody2D::_body_enter_tree(ObjectID p_id) {
Expand Down Expand Up @@ -1206,45 +1298,6 @@ Ref<KinematicCollision2D> CharacterBody2D::_get_slide_collision(int p_bounce) {
return slide_colliders[p_bounce];
}

void CharacterBody2D::set_sync_to_physics(bool p_enable) {
if (sync_to_physics == p_enable) {
return;
}
sync_to_physics = p_enable;

if (Engine::get_singleton()->is_editor_hint()) {
return;
}

if (p_enable) {
PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &CharacterBody2D::_direct_state_changed));
set_only_update_transform_changes(true);
set_notify_local_transform(true);
} else {
PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
set_only_update_transform_changes(false);
set_notify_local_transform(false);
}
}

bool CharacterBody2D::is_sync_to_physics_enabled() const {
return sync_to_physics;
}

void CharacterBody2D::_direct_state_changed(Object *p_state) {
if (!sync_to_physics) {
return;
}

PhysicsDirectBodyState2D *state = Object::cast_to<PhysicsDirectBodyState2D>(p_state);
ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState2D object as argument");

last_valid_transform = state->get_transform();
set_notify_local_transform(false);
set_global_transform(last_valid_transform);
set_notify_local_transform(true);
}

void CharacterBody2D::set_safe_margin(real_t p_margin) {
margin = p_margin;
}
Expand Down Expand Up @@ -1304,8 +1357,6 @@ void CharacterBody2D::set_up_direction(const Vector2 &p_up_direction) {
void CharacterBody2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
last_valid_transform = get_global_transform();

// Reset move_and_slide() data.
on_floor = false;
on_floor_body = RID();
Expand All @@ -1314,16 +1365,6 @@ void CharacterBody2D::_notification(int p_what) {
motion_results.clear();
floor_velocity = Vector2();
} break;

case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
// Used by sync to physics, send the new transform to the physics.
Transform2D new_transform = get_global_transform();
PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform);
// But then revert changes.
set_notify_local_transform(false);
set_global_transform(last_valid_transform);
set_notify_local_transform(true);
} break;
}
}

Expand Down Expand Up @@ -1356,9 +1397,6 @@ void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_slide_count"), &CharacterBody2D::get_slide_count);
ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody2D::_get_slide_collision);

ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &CharacterBody2D::set_sync_to_physics);
ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &CharacterBody2D::is_sync_to_physics_enabled);

ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stop_on_slope"), "set_stop_on_slope_enabled", "is_stop_on_slope_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "infinite_inertia"), "set_infinite_inertia_enabled", "is_infinite_inertia_enabled");
Expand All @@ -1367,7 +1405,6 @@ void CharacterBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "snap"), "set_snap", "get_snap");
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");
}

Expand Down
19 changes: 11 additions & 8 deletions scene/2d/physics_body_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ class StaticBody2D : public PhysicsBody2D {
Ref<PhysicsMaterial> physics_material_override;

bool kinematic_motion = false;
bool sync_to_physics = false;

Transform2D last_valid_transform;

void _direct_state_changed(Object *p_state);

protected:
void _notification(int p_what);
Expand All @@ -84,6 +89,8 @@ class StaticBody2D : public PhysicsBody2D {
Vector2 get_constant_linear_velocity() const;
real_t get_constant_angular_velocity() const;

virtual TypedArray<String> get_configuration_warnings() const override;

StaticBody2D();

private:
Expand All @@ -93,6 +100,9 @@ class StaticBody2D : public PhysicsBody2D {

void set_kinematic_motion_enabled(bool p_enabled);
bool is_kinematic_motion_enabled() const;

void set_sync_to_physics(bool p_enable);
bool is_sync_to_physics_enabled() const;
};

class RigidBody2D : public PhysicsBody2D {
Expand Down Expand Up @@ -243,7 +253,7 @@ class RigidBody2D : public PhysicsBody2D {

TypedArray<Node2D> get_colliding_bodies() const; //function for script

TypedArray<String> get_configuration_warnings() const override;
virtual TypedArray<String> get_configuration_warnings() const override;

RigidBody2D();
~RigidBody2D();
Expand Down Expand Up @@ -276,7 +286,6 @@ class CharacterBody2D : public PhysicsBody2D {
bool on_floor = false;
bool on_ceiling = false;
bool on_wall = false;
bool sync_to_physics = false;

Vector<PhysicsServer2D::MotionResult> motion_results;
Vector<Ref<KinematicCollision2D>> slide_colliders;
Expand All @@ -285,9 +294,6 @@ class CharacterBody2D : public PhysicsBody2D {

bool separate_raycast_shapes(PhysicsServer2D::MotionResult &r_result);

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;

Expand Down Expand Up @@ -329,9 +335,6 @@ class CharacterBody2D : public PhysicsBody2D {
int get_slide_count() const;
PhysicsServer2D::MotionResult get_slide_collision(int p_bounce) const;

void set_sync_to_physics(bool p_enable);
bool is_sync_to_physics_enabled() const;

CharacterBody2D();
~CharacterBody2D();
};
Expand Down