diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index ebbe0775dd3..5e3f9b6ead5 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -29,6 +29,8 @@ /**************************************************************************/ #include "skeleton_2d.h" +#include "core/engine.h" +#include "core/math/transform_interpolator.h" void Bone2D::_order_changed_in_parent() { if (skeleton) { @@ -270,20 +272,76 @@ Bone2D *Skeleton2D::get_bone(int p_idx) { return bones[p_idx].bone; } -void Skeleton2D::_notification(int p_what) { - if (p_what == NOTIFICATION_READY) { - if (bone_setup_dirty) { - _update_bone_setup(); - } - if (transform_dirty) { - _update_transform(); - } +void Skeleton2D::_update_process_mode() { + bool process = is_physics_interpolated_and_enabled() && is_visible_in_tree(); - request_ready(); + set_process_internal(process); + set_physics_process_internal(process); +} + +void Skeleton2D::_ensure_update_interpolation_data() { + uint64_t tick = Engine::get_singleton()->get_physics_frames(); + + if (_interpolation_data.last_update_physics_tick != tick) { + _interpolation_data.xform_prev = _interpolation_data.xform_curr; + _interpolation_data.last_update_physics_tick = tick; } +} - if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - VS::get_singleton()->skeleton_set_base_transform_2d(skeleton, get_global_transform()); +void Skeleton2D::_physics_interpolated_changed() { + _update_process_mode(); +} + +void Skeleton2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_READY: { + if (bone_setup_dirty) { + _update_bone_setup(); + } + if (transform_dirty) { + _update_transform(); + } + + request_ready(); + } break; + case NOTIFICATION_ENTER_TREE: { + _update_process_mode(); + + if (is_physics_interpolated_and_enabled()) { + _interpolation_data.xform_curr = get_global_transform(); + _interpolation_data.xform_prev = _interpolation_data.xform_curr; + } + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + if (is_physics_interpolated_and_enabled()) { + _ensure_update_interpolation_data(); + if (Engine::get_singleton()->is_in_physics_frame()) { + _interpolation_data.xform_curr = get_global_transform(); + } + } else { + VS::get_singleton()->skeleton_set_base_transform_2d(skeleton, get_global_transform()); + } + } break; + case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: { + _interpolation_data.xform_curr = get_global_transform(); + _interpolation_data.xform_prev = _interpolation_data.xform_curr; + } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + if (is_physics_interpolated_and_enabled()) { + _ensure_update_interpolation_data(); + _interpolation_data.xform_curr = get_global_transform(); + } + } break; + case NOTIFICATION_INTERNAL_PROCESS: { + if (is_physics_interpolated_and_enabled()) { + Transform2D res; + TransformInterpolator::interpolate_transform_2d(_interpolation_data.xform_prev, _interpolation_data.xform_curr, res, Engine::get_singleton()->get_physics_interpolation_fraction()); + VS::get_singleton()->skeleton_set_base_transform_2d(skeleton, res); + } + } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + _update_process_mode(); + } break; } } diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index 22773b8e4cb..31e1e6c85c4 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -101,10 +101,21 @@ class Skeleton2D : public Node2D { RID skeleton; + void _update_process_mode(); + void _ensure_update_interpolation_data(); + + struct InterpolationData { + Transform2D xform_curr; + Transform2D xform_prev; + uint32_t last_update_physics_tick = UINT32_MAX; + } _interpolation_data; + protected: void _notification(int p_what); static void _bind_methods(); + virtual void _physics_interpolated_changed(); + public: int get_bone_count() const; Bone2D *get_bone(int p_idx);