I'm building a collection of minigames in Godot, and I've run into a bit of a problem with the drag-and-drop mechanics. I've managed to implement this functionality into the game, however during testing I've discovered that when several objects are dragged one after the other very quickly, the previous object, which is not being currently dragged, may move with the one currently being dragged. I've tried to fix it by using call_deferred and such, but nothing seems to completely fix the issue.
Any advice would be appreciated! Perhaps there is a better way to implement the click-and-drag functionality? The draggable objects on the screen may overlap, which is why I'm using buttons instead of area2D, but maybe I'm wrong in doing that?
The Draggable hierarchy is:
- Draggable (TextureButton)
- - Area2D
- - - CollisionShape2D
The code for the draggable object:
class_name Draggable extends TextureButton
@export var drop_kind : String = ""
var draggable : bool = false
var is_inside_droppable : bool = false
var body_ref = null
var body_entered = null
var body_exited = null
var offset : Vector2
var initial_position : Vector2
var tween : Tween
func _ready():
initial_position = global_position
func _process(_delta):
if draggable:
if Input.is_action_just_pressed("click"):
initial_position = global_position
offset = get_global_mouse_position() - global_position
GlobalDragging.currently_dragging = true
if Input.is_action_pressed("click"):
global_position = get_global_mouse_position() - offset
elif Input.is_action_just_released("click"):
GlobalDragging.currently_dragging = false
if !is_inside_droppable:
if tween:
tween.kill()
tween = get_tree().create_tween()
tween.tween_property(self, "global_position", initial_position, 0.2).set_ease(Tween.EASE_OUT)
func _on_mouse_entered():
if !GlobalDragging.currently_dragging:
draggable = true
scale = Vector2(1.05, 1.05)
func _on_mouse_exited():
if !GlobalDragging.currently_dragging:
draggable = false
scale = Vector2(1.00, 1.00)
func on_drop_area_entered(body : Area2D):
body_entered = body
is_inside_droppable = true
body_ref = body
func on_drop_area_exited(body : Area2D):
body_exited = body
is_inside_droppable = false
The code for the drop area:
class_name DropArea extends Area2D
@export var drop_kind : String = ""
func _ready():
area_exited.connect(on_area_exited)
area_entered.connect(on_area_entered)
func on_area_entered(area : Area2D):
thumbs_up_emoji.call_deferred(area)
func on_area_exited(area : Area2D):
if drop_kind == area.get_parent().drop_kind:
area.get_parent().on_drop_area_exited(self)
func thumbs_up_emoji(area):
if drop_kind == area.get_parent().drop_kind:
area.get_parent().on_drop_area_entered(self)