Drag and Drop a Sprite. Is there a built in function for a Node?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By chrispalle

Hi -

Trying to drag and drop a sprite, I was able to get this to work. Basically, I detect the size and position of sprite and compare it to mouse_position. But I can’t help but think there is a better way. For one, I know I could remove some of those checks into variables to make it more readable. Also, the sprite snaps its center onto mouse pointer. I could clean this all up, but want to make sure I’m heading in the right direction or if there is an out of the box approach. (I know there is for Controls, but I don’t think those methods are accessible to Nodes). Any help is appreciated. Thanks !

var can_grab = false
var grabbed = false
#Location of where we grabbed the sprite
var grabbed_start = Vector2()

func _input(event):
	if event.is_action_pressed("click_left") and !grabbed:
		#detects that pointer is within dimension of Sprite
		if get_global_mouse_position().x > $Sprite.position.x - ($Sprite.texture.get_size().x/2) && get_global_mouse_position().x < $Sprite.position.x - ($Sprite.texture.get_size().x/2) + $Sprite.texture.get_size().x:
			if get_global_mouse_position().y > $Sprite.position.y - ($Sprite.texture.get_size().y/2) && get_global_mouse_position().y < $Sprite.position.y - ($Sprite.texture.get_size().x/2) + $Sprite.texture.get_size().y:
				grabbed = true
				grabbed_start = get_global_mouse_position()
	if event.is_action_released("click_left") and grabbed:
		grabbed = false
		var grabbed_end = get_global_mouse_position()
		$Sprite.position = event.position
		var sprite_pos = $Sprite.position
	elif event is InputEventMouseMotion:
		if grabbed:
			$Sprite.position = event.position
:bust_in_silhouette: Reply From: chrispalle

Okay. Found part of the answer. Looks like this was actually asked quite a bit.

The best way to do this is ensure the KinematicBody2D has its pickable flag set in the inspector. Then it can treating more like a GUI control and there’s no need work with the sprite’s texture.

Here’s a link: https://forum.godotengine.org/34536/simple-click-2d-how-to-tell-when-static-body-has-been-clicked

For the mouse pointer snapping issue (if this is not a desired effect for you), just find the difference of the offset and add it back in when the object is clicked. Still a little delay on the drag, but I think this could be taken care of with a tween behavior to make it feel a little more intentional, but that’s just my opinion. good luck.

extends KinematicBody2D

# Pickable needs to be selected from the inspector

var can_grab = false
var grabbed_offset = Vector2()

func _input_event(viewport, event, shape_idx):
	if event is InputEventMouseButton:
		can_grab = event.pressed
		grabbed_offset = position - get_global_mouse_position()

func _process(delta):
	if Input.is_mouse_button_pressed(BUTTON_LEFT) and can_grab:
		position = get_global_mouse_position() + grabbed_offset

1 year later in this comment still comes in clutch. That part about the offset saved me on such a headache, ty!

WhetPotato | 2020-09-15 23:58

:bust_in_silhouette: Reply From: angstyloop
:bust_in_silhouette: Reply From: gemmomoh

This works and would drag the object when the mouse button is down and stops dragging as soon as it’s released

var canDrag = false

func _process(delta):
	if canDrag:
		$".".global_position = lerp($".".global_position, get_global_mouse_position(), 10 * delta)

func _input_event(viewport, event, shape_idx):
	if event is InputEventMouseMotion:
		if event.button_mask == 1 and event.pressure == 1.00:
			canDrag = true
			canDrag = false

Just incase anyone still needs this, I’m pretty sure there’s an addon that adds this.