Sensivity of InputEventScreenTouch/Drag

Godot Version

4.3

Question

Hi everyone!

I’m using both InputEventScreenTouch and InputEventScreenDrag for mobile player inputs, but I’m facing an issue regarding sensitivity when swiping.

func _unhandled_input(event: InputEvent) -> void:
	if state != CubesetState.IDLE:
		return
	if event is InputEventScreenDrag:
		if event.relative.y > 0:
			if event.position.y >= get_viewport_rect().size.y * 0.8:
				cubeset_input.emit(self, 0, Vector2i(0, DOWN_MOVE))
		else:
			if cubes.size() > 1:
				switch_cubes()

In my unhandled_input() method I have this part where a pair of cubes will be moved down. The problem is that the cubes moves to fast! The minimum swipe on down direction moves a lot. That DOWN_MOVE constant means 30 pixels.

The same thing for that switch_cubes() method. This method just swaps the position of each cube from the pair, so the cube on the left goes to the position on the right and vice-versa. But swiping up makes the pair switches positions several times. The swipe must be really smooth to move just once and change the positions properly.

How can I control the sensitivity of the these drag inputs?

InputEvents are emitted at least once per frame (unless Input.use_accumulated_input is disabled) so, if you drag for 30 frames you’ll receive 30 InputEventScreenDrag events.

In your example, if you swipe down 30 frames the signal cubeset_input will emit 30 times and if you swipe up 30 frames the switch_cubes() function will be called 30 times.

You could try to use InputEventScreenDrag.velocity instead, have a threshold both positive and negative, and only emit the signal or call the function one time once that threshold has been surpassed.

You could try to rate limit with a timer. Add a timer. Set it to 0.1 second. Make it one-shot.

@onready var timer: Timer = $Timer


var can_drag = true


func _ready() -> void:
	timer.timeout.connect(_on_timeout)


func _unhandled_input(event: InputEvent) -> void:
	if state != CubesetState.IDLE:
		return
	if event is InputEventScreenDrag and can_drag:
		can_drag = false
		timer.start()
		if event.relative.y > 0:
			if event.position.y >= get_viewport_rect().size.y * 0.8:
				cubeset_input.emit(self, 0, Vector2i(0, DOWN_MOVE))
		else:
			if cubes.size() > 1:
				switch_cubes()


func _on_timeout():
	can_drag = true

Looks interesting, let me try that and I’ll update this post.