|
@@ -974,6 +974,10 @@ Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_inf
|
|
|
}
|
|
|
|
|
|
bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) {
|
|
|
+ if (sync_to_physics) {
|
|
|
+ ERR_PRINT("Functions move_and_slide and move_and_collide do not work together with 'sync to physics' option. Please read the documentation.");
|
|
|
+ }
|
|
|
+
|
|
|
Transform gt = get_global_transform();
|
|
|
PhysicsServer::MotionResult result;
|
|
|
bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result, p_exclude_raycast_shapes);
|
|
@@ -1019,8 +1023,17 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ Vector3 current_floor_velocity = floor_velocity;
|
|
|
+ if (on_floor && on_floor_body.is_valid()) {
|
|
|
+ // This approach makes sure there is less delay between the actual body velocity and the one we saved.
|
|
|
+ PhysicsDirectBodyState *bs = PhysicsServer::get_singleton()->body_get_direct_state(on_floor_body);
|
|
|
+ if (bs) {
|
|
|
+ current_floor_velocity = bs->get_linear_velocity();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
|
|
|
- Vector3 motion = (floor_velocity + body_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time());
|
|
|
+ Vector3 motion = (current_floor_velocity + body_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time());
|
|
|
|
|
|
on_floor = false;
|
|
|
on_floor_body = RID();
|
|
@@ -1241,8 +1254,50 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) {
|
|
|
return slide_colliders[p_bounce];
|
|
|
}
|
|
|
|
|
|
+void KinematicBody::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) {
|
|
|
+ PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
|
|
|
+ set_only_update_transform_changes(true);
|
|
|
+ set_notify_local_transform(true);
|
|
|
+ } else {
|
|
|
+ PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), nullptr, "");
|
|
|
+ set_only_update_transform_changes(false);
|
|
|
+ set_notify_local_transform(false);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool KinematicBody::is_sync_to_physics_enabled() const {
|
|
|
+ return sync_to_physics;
|
|
|
+}
|
|
|
+
|
|
|
+void KinematicBody::_direct_state_changed(Object *p_state) {
|
|
|
+ if (!sync_to_physics) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ PhysicsDirectBodyState *state = Object::cast_to<PhysicsDirectBodyState>(p_state);
|
|
|
+ ERR_FAIL_COND_MSG(!state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState 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);
|
|
|
+ _on_transform_changed();
|
|
|
+}
|
|
|
+
|
|
|
void KinematicBody::_notification(int p_what) {
|
|
|
if (p_what == NOTIFICATION_ENTER_TREE) {
|
|
|
+ last_valid_transform = get_global_transform();
|
|
|
+
|
|
|
// Reset move_and_slide() data.
|
|
|
on_floor = false;
|
|
|
on_floor_body = RID();
|
|
@@ -1251,6 +1306,17 @@ void KinematicBody::_notification(int p_what) {
|
|
|
colliders.clear();
|
|
|
floor_velocity = Vector3();
|
|
|
}
|
|
|
+
|
|
|
+ if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
|
|
|
+ //used by sync to physics, send the new transform to the physics
|
|
|
+ Transform new_transform = get_global_transform();
|
|
|
+ PhysicsServer::get_singleton()->body_set_state(get_rid(), PhysicsServer::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);
|
|
|
+ _on_transform_changed();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void KinematicBody::_bind_methods() {
|
|
@@ -1275,11 +1341,17 @@ void KinematicBody::_bind_methods() {
|
|
|
ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody::get_slide_count);
|
|
|
ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody::_get_slide_collision);
|
|
|
|
|
|
+ ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &KinematicBody::set_sync_to_physics);
|
|
|
+ ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &KinematicBody::is_sync_to_physics_enabled);
|
|
|
+
|
|
|
+ ClassDB::bind_method(D_METHOD("_direct_state_changed"), &KinematicBody::_direct_state_changed);
|
|
|
+
|
|
|
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_x", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X);
|
|
|
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_y", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y);
|
|
|
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_z", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z);
|
|
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "motion/sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled");
|
|
|
}
|
|
|
|
|
|
KinematicBody::KinematicBody() :
|