For the past week, I’ve been working on the controls for a mobile game but I’m having troubles with multi-touch and screen drag.
I have two arrows, one moves the player right, and the other moves him left. I need both of them to be clickable at the same time (eg. when the player presses the jump button while going left) and I’d like to implement “pass-by press” (like TouchScreenButton’s).
I can’t use TouchScreenButton though, since it has too few options and it isn’t a Control node.
I tried to make a custom one myself, and so far I’ve achieved this:
func _on_texture_gui_input(event):
if event is InputEventScreenTouch:
if event.pressed:
pressed.emit()
# Animate the button
$Texture.scale = Vector2(1.2, 1.2)
set_process(true)
is_pressed = event.pressed
elif event is InputEventScreenDrag:
# Detect if drag is outside the texture
if not Rect2(Vector2(0,0), $Texture.get_global_rect().size).has_point(event.position):
# Cancel event
pass
else:
pressed.emit()
It works with multi-touch using a texture internally but I can’t implement “pass-by press”, as this gif shows.
The code is able to detect when the finger is out of the button but I need a way to “cancel” the input so the other button can receive it. Thanks for the help.
_gui_input() gets attached to the Control that started the click/touch. You’ll need to use _input() in the TextureRect itself. Something like this may work:
extends TextureRect
signal pressed()
var is_pressed = false
func _input(event: InputEvent) -> void:
if event is InputEventScreenTouch:
if get_global_rect().has_point(event.position):
is_pressed = event.pressed
if is_pressed:
pressed.emit()
if event is InputEventScreenDrag:
if get_global_rect().has_point(event.position):
pressed.emit()
Thank you for the answer, I applied your code to the texture node, and now the Control node “Button” only holds the ‘is_pressed’ boolean and 'pressed ’ signal.
I added some debugging to the code you provided…
# ...
if event is InputEventScreenDrag:
if get_global_rect().has_point(event.position):
get_parent().pressed.emit()
print("Still pressed")
else:
print("Not pressed")
…and as shown in this clip, the button remains pressed even when the cursor is outside and has released.
So, as before, there’s a way to detect that (when the event is InputScreenDrag and the position isn’t in the bounding box) but I don’t know how to stop the event.
Keep the event index and change is_pressed when that event index gets released:
extends TextureRect
signal pressed()
var is_pressed = false
var touch_idx = -1
func _input(event: InputEvent) -> void:
if event is InputEventScreenTouch:
if get_global_rect().has_point(event.position):
is_pressed = event.pressed
touch_idx = event.index
if is_pressed:
pressed.emit()
elif not event.pressed and event.index == touch_idx:
is_pressed = false
touch_idx = -1
if event is InputEventScreenDrag:
if get_global_rect().has_point(event.position):
pressed.emit()