SpyrexDE / SmoothScroll

Addon for the Godot Game Engine that adds a SmoothScrollContainer.
https://spyrexde.github.io/SmoothScroll/
MIT License
132 stars 10 forks source link

Fix overdrag bounce problem and follow focus #12

Closed HaroldLever closed 1 year ago

HaroldLever commented 1 year ago

Over dragging with high speed would make it bounce back too much, not like touch screen app. I managed to use an inelegant way to bounce back to boundary.

Also, I found the #2 solution is to set_input_as_handled() to avoid the original scroll container receiving input event. I guess it is because the original scroll container does not allow content moving outside, it tries to pull it back when receiving input event. Not sure it is a glitch of Godot or not. But set_input_as_handled() makes it loses the ability to pass input event, maybe there is a better solution.

To avoid over drag too much, I add an exported an Enum that allows users to set up over drag zone.

Following focus now is more accurate, due to scroll_to(y_pos) uses tween now.

SpyrexDE commented 1 year ago

Thanks for the pull request! However, there are a few things I would like to point out:

  1. What is the purpose/example use case of having different over-drag zones?
  2. When over-dragging more than the over-drag zones allows, there is an error: Invalid set index 'position' (on base: 'Control') with value of type 'float'.
  3. I would really like to keep applying a counterforce when over-dragging, just like it is with e.g. Apple devices.
HaroldLever commented 1 year ago

Thank you for pointing out these problems and I am working on them. Hopefully I didn't make a mess.

  1. This is mainly for the situation when releasing dragging, it still retains a very high speed, resulting in over scrolling distance is too long or even beyond the container. Personally, taking much time and distance to bounce back doesn't look good. There might be users who don't want over dragging at all, or would like to customize over drag zone.

    • Disabled: not allow over drag at all, the same as custom_overdrag_zone = 0.0
    • Full Rect: allow over drag 'till the other side of scroll container, the same as custom_overdrag_zone = self.size.y
    • Infinity: no limit over drag
    • Custom: use custom_overdrag_zone value
  2. Unfortunately, I failed to reappear this error. Is it convenient for you to provide reappear steps or execution files?

  3. Agreed, I am also reworking the bounce back method to see if I could preserve the formula. But I failed to conclude the velocity = f(time) formula, could you share your thoughts about velocity.y = lerp(velocity.y, -top_distance/8, damping) , getting the formula would be a great help for me.

SpyrexDE commented 1 year ago

This is mainly for the situation when releasing dragging, it still retains a very high speed, resulting in over scrolling distance is too long or even beyond the container.

I noticed that problem as well, however, it was only present when using the touch controls. Using the mouse wheel it worked perfectly.

There might be users who don't want over dragging at all, or would like to customize over drag zone.

Generally, this was meant to be customizable by changing the damping value. The higher the value, the harder is it to over-drag. Having a dedicated drag zone results in unnatural behavior where either the damping is too soft for that small drag zone or the other way around. The damping value is an important indicator for the user of how far you can over-drag.

Unfortunately, I failed to reappear this error. Is it convenient for you to provide reappear steps or execution files?

Probably I am using a different version of the Godot 4 beta. Which one are you using? I was using Beta 2. Just tried it out with Beta 16 but there were many visual issues.

could you share your thoughts about velocity.y = lerp(velocity.y, -top_distance/8, damping)

Well, I added a counterforce calculated by the distance that was over dragged and divided it by eight. The eight is just a constant that felt natural for me.

HaroldLever commented 1 year ago

Hi, SpyrexDE. I managed to fix bounce problem in a new way, and I preserve your bounce formula as much as I can. And I withdraw the over drag zone commit and force push it.

You would notice that I make some change to wheel button event. Wheel button actually gets 2 events at the same time: pressed and not pressed. This is why it gets +=2*speed, which might not be accurate. I choose the pressed event and change the default speed value. And I change its range, now the value can be greater.

SpyrexDE commented 1 year ago

Thank you! Now it feels much better, however, there is still a counterforce missing when over-dragging using touch controls, and the snapping back after over-dragging with touch controls is noticeably slower than when using the mouse wheel.

HaroldLever commented 1 year ago

No idea for now, but I found increasing damping value might help. Would you like a new exported var called "damping_drag", and change "damping" as "damping_scroll"?

SpyrexDE commented 1 year ago

I feel like the real issue lies in different easing curves. Whereas the scroll over-drag feels more like an easeOutQuart, the touch over-drag feels more like an easeOutExpo.

Both have scroll and drag friction set to 0.9 and scroll and drag damping to 0.1.

Edit: Probably it's not the easing curves but actually just the touch one behaving the same as the scroll one but just a lot slower. If the easing really were the problem, they would have to stop moving at the same time, which is not the case.

HaroldLever commented 1 year ago

😵‍💫Really weird situation. They share the same formula before #24b113d. But I think it's just ok by splitting it into two variables, for it might not be that necessary to make them exactly the same. Users can change the value individually. What do you think?

SpyrexDE commented 1 year ago

I think having the possibility to change the touch over-drag behavior separately to the scroll one is indeed a good thing, but the default values should be the same and behave the same.

SpyrexDE commented 1 year ago

Oh, I am really sorry. Just noticed that in my example from above, I forgot to adjust one value. It's actually all behaving correctly. I would just prefer to set the default values the same for scroll and touch drag 👍

SpyrexDE commented 1 year ago

Thanks a lot for your contribution! The next thing would be to implement a counterforce for touch over-dragging. I already fiddled around a bit and came to the conclusion that such a mechanic is a bit more complex than it might seem at first. On Apple devices, over-dragging with touch is implemented in such a way, that as soon as the content gets over-dragged, the y-position of the gesture gets saved and the speed gets increasingly slower as the more you drag away from that position. The speed increases again when moving the finger toward that position and as soon you reach that position the speed is normal again. In this way, it feels like a seamless transition from something like a scroll and a stretching state.

SpyrexDE commented 1 year ago

I just moved that over-drag for touch controls feature to a dedicated issue: #13 Feel free to make a pull request if you got a good solution :)