diff options
Diffstat (limited to 'scene/2d/camera_2d.cpp')
-rw-r--r-- | scene/2d/camera_2d.cpp | 117 |
1 files changed, 97 insertions, 20 deletions
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 722858b674..18ef2d8505 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -54,11 +54,18 @@ void Camera2D::_update_scroll() { if (is_current()) { ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id)); - Transform2D xform = get_camera_transform(); + Size2 screen_size = _get_camera_screen_size(); + + Transform2D xform; + if (is_physics_interpolated_and_enabled()) { + xform = _interpolation_data.xform_prev.interpolate_with(_interpolation_data.xform_curr, Engine::get_singleton()->get_physics_interpolation_fraction()); + camera_screen_center = xform.affine_inverse().xform(0.5 * screen_size); + } else { + xform = get_camera_transform(); + } viewport->set_canvas_transform(xform); - Size2 screen_size = _get_camera_screen_size(); Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5) : Point2()); Point2 adj_screen_pos = camera_screen_center - (screen_size * 0.5); @@ -68,15 +75,26 @@ void Camera2D::_update_scroll() { } void Camera2D::_update_process_callback() { - if (_is_editing_in_editor()) { + if (is_physics_interpolated_and_enabled()) { + set_process_internal(is_current()); + set_physics_process_internal(is_current()); + +#ifdef TOOLS_ENABLED + if (process_callback == CAMERA2D_PROCESS_IDLE) { + WARN_PRINT_ONCE("Camera2D overridden to physics process mode due to use of physics interpolation."); + } +#endif + } else if (_is_editing_in_editor()) { set_process_internal(false); set_physics_process_internal(false); - } else if (process_callback == CAMERA2D_PROCESS_IDLE) { - set_process_internal(true); - set_physics_process_internal(false); } else { - set_process_internal(false); - set_physics_process_internal(true); + if (process_callback == CAMERA2D_PROCESS_IDLE) { + set_process_internal(true); + set_physics_process_internal(false); + } else { + set_process_internal(false); + set_physics_process_internal(true); + } } } @@ -161,8 +179,15 @@ Transform2D Camera2D::get_camera_transform() { } } + // FIXME: There is a bug here, introduced before physics interpolation. + // Smoothing occurs rather confusingly during the call to get_camera_transform(). + // It may be called MULTIPLE TIMES on certain frames, + // therefore smoothing is not currently applied only once per frame / tick, + // which will result in some haphazard results. if (position_smoothing_enabled && !_is_editing_in_editor()) { - real_t c = position_smoothing_speed * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time()); + bool physics_process = (process_callback == CAMERA2D_PROCESS_PHYSICS) || is_physics_interpolated_and_enabled(); + real_t delta = physics_process ? get_physics_process_delta_time() : get_process_delta_time(); + real_t c = position_smoothing_speed * delta; smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos; ret_camera_pos = smoothed_camera_pos; //camera_pos=camera_pos*(1.0-position_smoothing_speed)+new_camera_pos*position_smoothing_speed; @@ -223,17 +248,52 @@ Transform2D Camera2D::get_camera_transform() { return xform.affine_inverse(); } +void Camera2D::_ensure_update_interpolation_data() { + // The "curr -> previous" update can either occur + // on NOTIFICATION_INTERNAL_PHYSICS_PROCESS, OR + // on NOTIFICATION_TRANSFORM_CHANGED, + // if NOTIFICATION_TRANSFORM_CHANGED takes place earlier than + // NOTIFICATION_INTERNAL_PHYSICS_PROCESS on a tick. + // This is to ensure that the data keeps flowing, but the new data + // doesn't overwrite before prev has been set. + + // Keep the data flowing. + 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; + } +} + void Camera2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_INTERNAL_PROCESS: - case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + case NOTIFICATION_INTERNAL_PROCESS: { _update_scroll(); } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + if (is_physics_interpolated_and_enabled()) { + _ensure_update_interpolation_data(); + _interpolation_data.xform_curr = get_camera_transform(); + } else { + _update_scroll(); + } + } break; + + case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: { + // Force the limits etc. to update. + _interpolation_data.xform_curr = get_camera_transform(); + _interpolation_data.xform_prev = _interpolation_data.xform_curr; + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { - if (!position_smoothing_enabled || _is_editing_in_editor()) { + if ((!position_smoothing_enabled && !is_physics_interpolated_and_enabled()) || _is_editing_in_editor()) { _update_scroll(); } + if (is_physics_interpolated_and_enabled()) { + _ensure_update_interpolation_data(); + _interpolation_data.xform_curr = get_camera_transform(); + } } break; case NOTIFICATION_ENTER_TREE: { @@ -260,6 +320,15 @@ void Camera2D::_notification(int p_what) { _update_process_callback(); first = true; _update_scroll(); + + // Note that NOTIFICATION_RESET_PHYSICS_INTERPOLATION + // is automatically called before this because Camera2D is inherited + // from CanvasItem. However, the camera transform is not up to date + // until this point, so we do an extra manual reset. + if (is_physics_interpolated_and_enabled()) { + _interpolation_data.xform_curr = get_camera_transform(); + _interpolation_data.xform_prev = _interpolation_data.xform_curr; + } } break; case NOTIFICATION_EXIT_TREE: { @@ -431,12 +500,17 @@ void Camera2D::_make_current(Object *p_which) { queue_redraw(); - if (p_which == this) { + bool was_current = viewport->get_camera_2d() == this; + bool is_current = p_which == this; + + if (is_current) { viewport->_camera_2d_set(this); - } else { - if (viewport->get_camera_2d() == this) { - viewport->_camera_2d_set(nullptr); - } + } else if (was_current) { + viewport->_camera_2d_set(nullptr); + } + + if (is_current != was_current) { + _update_process_callback(); } } @@ -456,6 +530,7 @@ void Camera2D::make_current() { _make_current(this); } _update_scroll(); + _update_process_callback(); } void Camera2D::clear_current() { @@ -468,6 +543,8 @@ void Camera2D::clear_current() { if (!custom_viewport || ObjectDB::get_instance(custom_viewport_id)) { viewport->assign_next_enabled_camera_2d(group_name); } + + _update_process_callback(); } bool Camera2D::is_current() const { @@ -552,7 +629,7 @@ void Camera2D::align() { } void Camera2D::set_position_smoothing_speed(real_t p_speed) { - position_smoothing_speed = p_speed; + position_smoothing_speed = MAX(0, p_speed); _update_process_internal_for_smoothing(); } @@ -561,7 +638,7 @@ real_t Camera2D::get_position_smoothing_speed() const { } void Camera2D::set_rotation_smoothing_speed(real_t p_speed) { - rotation_smoothing_speed = p_speed; + rotation_smoothing_speed = MAX(0, p_speed); _update_process_internal_for_smoothing(); } @@ -802,7 +879,7 @@ void Camera2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_margin_drawing_enabled"), &Camera2D::is_margin_drawing_enabled); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_mode", PROPERTY_HINT_ENUM, "Fixed TopLeft,Drag Center"), "set_anchor_mode", "get_anchor_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_mode", PROPERTY_HINT_ENUM, "Fixed Top Left,Drag Center"), "set_anchor_mode", "get_anchor_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_rotation"), "set_ignore_rotation", "is_ignoring_rotation"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom", PROPERTY_HINT_LINK), "set_zoom", "get_zoom"); |