2
\$\begingroup\$

I'm trying to make a simple drag and drop function, and it works when dragging from one area to another, but if I accidentally drop the sprite outside the allowed areas, it just disappears. I've been trying to have it set up so that the sprite, if dropped outside the area, returns to its last known location. Here is the code I have, although it does not work as the sprite still disappears:

extends TextureRect

var original_position : Vector2

func _get_drag_data(at_position):
    original_position = position
    
    var preview_texture = TextureRect.new()
    preview_texture.texture = texture
    preview_texture.expand_mode = 1
    preview_texture.size = Vector2(90,90)
    
    var preview = Control.new()
    preview.add_child(preview_texture)
    
    set_drag_preview(preview)
    
    
    texture = null
    return preview_texture.texture
    
func _can_drop_data(at_position, data):
    return data is Texture2D
    
func _drop_data(at_position, data):
    if _can_drop_data(at_position, data):
        texture = data
    else:
        texture = data
        position = original_position

My node tree looks like:

  • Node2D
    • TextureRect
      • Panel
    • TextureRect
      • Panel
\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

Before Godot calls _drop_data, it will call _can_drop_data. Furthermore, if _can_drop_data returned false, Godot will not call _drop_data.

So in this code:

func _can_drop_data(at_position, data):
    return data is Texture2D
    
func _drop_data(at_position, data):
    if _can_drop_data(at_position, data):
        texture = data
    else:
        texture = data
        position = original_position

Calling _can_drop_data from _drop_data is redundant, and the execution flow will never enter the else statement.


The above, of course, is only called when attempting to drop on the TextureRect with the shown script. So that code won't handle dropping outside.

Try checking for NOTIFICATION_DRAG_END in _notification, where you can check if drag failed:

func _notification(what:int) -> void:
    if what == NOTIFICATION_DRAG_END and not is_drag_successful():
        print("Drag Failed")
\$\endgroup\$
2
  • \$\begingroup\$ How would I be able to have it reappear in its original location though? This does say that the drag is not successful, but it does not provide any insight on how to get it to go back to its original position. I tried incorporating the is_drag_successful() function into the _drop_data() function but that did not change anything. \$\endgroup\$
    – lzzard
    Commented Dec 18, 2023 at 4:06
  • \$\begingroup\$ @lzzard Is there any reason you can't put the code for that inside _notification? \$\endgroup\$
    – Theraot
    Commented Dec 18, 2023 at 4:20
0
\$\begingroup\$

First, store the original texture in your _get_drag_data function in a global variable:

    original_texture = preview_texture.texture

Next, you need to change the order in your else clause so that you set change the original position before you set the texture:

func _can_drop_data(at_position, data):
    return data is Texture2D
    
func _drop_data(at_position, data):
    if _can_drop_data(at_position, data):
        texture = data
    else:
        position = original_position
        texture = data

Then in the notification you can restore the panel texture back to the original texture on failure:

func _notification(what:int) -> void:
    if what == NOTIFICATION_DRAG_END and not is_drag_successful():
        texture = original_texture
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .