InputEventScreenDrag not keeping up when movement is too fast

Godot Version

4.3

Question

I am simply using InputEventScreenDrag to drag a Area2D node around. However, speed seems to be an issue when dragging the node faster. Ideally, I want the node to keep up, but it seems to lag behind and eventually disconnect from the drag.

Code

extends Area2D

var activated = false
# Called when the node enters the scene tree for the first time.
func _ready():
	pass
	
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
	pass
	
func _on_input_event(viewport, event, shape_idx):
	if event is InputEventScreenTouch:
		if event.pressed:
			activated = true
		else:
			activated = false
			
	if event is InputEventScreenDrag and activated:
		position = event.position
		

Demo

I am not sure it will work, but try this:

extends Area2D

var activated = false

var target_pos = Vector2.ZERO

# Called when the node enters the scene tree for the first time.
func _ready():
	pass
	
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
	if activated: position = lerp(position, target_pos, delta * 10.0)
	
func _on_input_event(viewport, event, shape_idx):
	if event is InputEventScreenTouch:
		if event.pressed:
			activated = true
		else:
			activated = false
			
	if event is InputEventScreenDrag and activated:
		target_pos = event.position

Hey thanks for replying. It still can’t keep up with the speed. I have a feeling some workaround with process() would be the way to fix it, but really can’t find any resources with faster polling and processing of InputEvent.

Please can you use physical process? Then tell me the result.

Unfortunately no luck when using _physics_process()

I haven’t tested the build on my iPad, only testing on my computer. I am hoping that because I am using ā€˜Emulate Touch from Mouse’, the emulation is the problem. Maybe simply building the game on my tablet will not have the same issue.

Hi @gavyn-ezell , did you manage to find a solution to this?

I recommend a different approarch using _process callback to move the node:

extends Area2D


# --- Signals --- #
# --- Enums --- #
# --- Constants --- #
# --- Exported Variables --- #
# --- Public Variables --- #
# --- Private Variables --- #
# --- Onready Variables --- #


# --- Engine Callbacks --- #
func _ready() -> void:
	# Turn off the _process to not drag after start
	set_process(false)


func _process(delta: float) -> void:
	# Set the position for the mouse position, using emulate mouse from touch 
	# will make it work on mobile (already turned on by default in project settings)
	global_position = get_global_mouse_position()


func _input(event: InputEvent) -> void:
	if event is InputEventScreenTouch:
		# When the event is a touch being released and _process is on, turn off _process
		if event.pressed == false and is_processing():
			set_process(false)


# --- Public Functions --- #


# --- Private Functions --- #
# - Common Use Functions - #
# - Setget Functions - #


# - Signal Functions - #
func _on_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
	# When a sceen touch inside the area is detected, turn on _process to start the drag
	if event is InputEventScreenTouch and event.pressed:
		set_process(true)

1 Like

Yeah I made sure to use _input(event) in the main scene code instead of _on_input_event(). This made the tracking a lot better and I could move a test sprite around at a higher speed. Don’t really understand it quite well but I can also show what I did if you need.

1 Like

@matheusmdx @gavyn-ezell thanks both for the pointers.

This seems to work as i intended:

EDIT for readers from the future
I did some changes to support both mouse and touch on mobile phone.
Add filter on event index to avoid weird behavior when multi touching.
ā€œEmulate Touch from mouseā€ and ā€œEmulate mouse from touchā€ should be set to true.

extends Node2D

var _dragging: bool = false
func _input(event: InputEvent) -> void:
	if _dragging and event is InputEventScreenDrag:
		var dragEvent: InputEventScreenDrag = event
		if dragEvent.index > 0:
			return
		position += dragEvent.relative
		get_viewport().set_input_as_handled()

func _on_area_2d_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
	if event is InputEventScreenTouch:
		var touchEvent: InputEventScreenTouch = event
		if touchEvent.index > 0:
			return
		_dragging = event.pressed