0 votes

Hi everyone,

I have my scroll-container up and running for mobile-tochscreen and everything scrolls smoothly „freely“ when I do a swipe until the scrolling gradually comes to a halt. This is my code:

extends ScrollContainer

var swiping = false
var button_down = false
var swipe_start
var swipe_mouse_start
var swipe_mouse_times = []
var swipe_mouse_positions = []

signal finger_started_swiping
signal finger_stopped_swiping

func _ready():
    mouse_filter = Control.MOUSE_FILTER_IGNORE

func _on_Button_button_down(): # coming from buttons within this container
    print ("button down")
    button_down = true
    swiping = false

func _input(ev):
# swiping to be possible only within the container-area:
    if (!self.get_global_rect().has_point(ev.position)):
        swiping = false
        return

    if ev is InputEventMouseButton:
        if ev.pressed:
            swiping = true
            if not button_down:
                emit_signal("finger_started_swiping")

            swipe_start = Vector2(get_h_scroll(), get_v_scroll())
            swipe_mouse_start = ev.position
            swipe_mouse_times = [OS.get_ticks_msec()]
            swipe_mouse_positions = [swipe_mouse_start]
        else:
            swipe_mouse_times.append(OS.get_ticks_msec())
            swipe_mouse_positions.append(ev.position)
            var source = Vector2(get_h_scroll(), get_v_scroll())
            #var idx = swipe_mouse_times.size() - 1 # original
            var idx = swipe_mouse_times.size() - 1
            var now = OS.get_ticks_msec()
            var cutoff = now - 100

            for i in range(swipe_mouse_times.size() - 1, -1, -1):
                if swipe_mouse_times[i] >= cutoff: idx = i
                else: break

            var flick_start = swipe_mouse_positions[idx]
            var flick_dur = min(0.7, (ev.position - flick_start).length() / 500)
# for smooth swiping:
            if flick_dur > 0.0:
                var tween = Tween.new()
                add_child(tween)
                var delta = ev.position - flick_start
                var target = source - delta * flick_dur * 8.0
                #tween.interpolate_method(self, 'set_h_scroll', source.x, target.x, flick_dur, Tween.TRANS_QUAD, Tween.EASE_OUT)
                tween.interpolate_method(self, 'set_v_scroll', source.y, target.y, flick_dur, Tween.TRANS_QUAD, Tween.EASE_OUT)
                tween.interpolate_callback(tween, flick_dur, 'queue_free')
                tween.start()

            if flick_dur == 0:
                print ("finger released --- not moving")

            swiping = false
            if not button_down:
                emit_signal("finger_stopped_swiping")

    elif swiping and ev is InputEventMouseMotion:
        var delta = ev.position - swipe_mouse_start
        set_h_scroll(swipe_start.x - delta.x)
        set_v_scroll(swipe_start.y - delta.y)
        swipe_mouse_times.append(OS.get_ticks_msec())
        swipe_mouse_positions.append(ev.position)

The problem is: if I put my finger down while the smooth „free“ scrolling is still going on, it doesn't stop, but will, when the scrolling ends, jump back to the position where my finger touched.
How could I have the scrolling instantly stop when touching the screen?

Unfortunately the signals scrollstarted() and scrollended() won't fire. These would be helpful... any ideas?

Godot version 3.3
in Engine by (365 points)

1 Answer

0 votes
Best answer

In the meantime, I put up this solution: I added a var tween_running = false and put tween_running = true right under tween.start(). At the beginning of func _input(ev): I added

if ev.is_action_pressed("mousebuttonclick"):
  if tween_running:
    tween.stop(self)

The only issue now is that the line add_child(tween) now throws the error

add_child: Can't add child to 'ScrollContainer', already has a parent 'ScrollContainer'.

It doesn't crash the program at least. But still, any idea how I could get rid of the error?

EDIT:

...and of course, minutes later I found the easy fix.

Place a "real" Tween Node as a child of the ScrollContainer.
Get rid of var tween = Tween.new() and add_child(tweenG).
Replace all tween with $Tween.

The whole thing works like a charm (for now ;) ...

by (365 points)
selected by
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.